Laravel Eloquentとは?使い方の基本からCRUD・リレーション・クエリビルダとの違いまで徹底解説

Laravel入門

Laravelでデータベースを操作する際、「Eloquent(エロクアント)って結局何ができるの?」「生のSQLやクエリビルダとどう違うの?」「リレーションやN+1問題はどう書けばいい?」と疑問を持つ方は多いのではないでしょうか。

Eloquentは、Laravelに標準搭載されている強力なORM(Object-Relational Mapping / オブジェクト関係マッピング)です。データベースのテーブルをPHPの「モデルクラス」として扱い、SQLを直接書くことなく直感的なメソッドチェーンで直感的にCRUD(作成・取得・更新・削除)やテーブル結合(リレーション)を実行できます。

この記事では、Laravel Eloquentの基本概念からモデルの作成、マスアサインメント、基本のCRUD操作、リレーション定義、N+1問題の対策、属性キャスト、クエリビルダとの違い、実務でつまずきやすいエラー対処法まで、初心者向けに動くコード例付きで徹底解説します。

結論として、Eloquentは「1テーブル=1モデルクラス」で対応づけ、User::find(1)Post::where('status', 'published')->get()のようにPHPらしい記述で安全かつ効率的にDB操作ができる仕組みです。基本のCRUD、hasManybelongsToなどのリレーション、そしてEagerローディング(with())によるN+1対策を押さえることで、Laravel開発の生産性は劇的に向上します。

※本記事はLaravel 11.x/12.x/13.x(PHP 8.2以上)をベースに解説しています。Laravel 9以降の無名クラスマイグレーションや、Laravel 11以降推奨のcasts()メソッド、スコープ記法など、バージョン差がある箇所は補足付きで説明しています。

  1. Laravel Eloquentとは?基本概念と特徴
    1. Eloquentを使う3つの大きなメリット
  2. モデルの作成と基本設定
    1. 1. Artisanコマンドでモデルを作成する
    2. 2. マイグレーションでテーブルを定義する
    3. 3. モデルの命名規則とカスタマイズ
    4. 4. マスアサインメント対策($fillable と $guarded)
  3. Eloquentの基本CRUD操作
    1. 1. Create(データの作成・保存)
      1. 新規インスタンスを作成して save()
      2. create() メソッドで一括作成
      3. firstOrCreate() と updateOrCreate()
    2. 2. Read(データの取得・検索)
      1. 全件取得と主キー検索
      2. 条件検索(where / orWhere / whereIn)
      3. 特定カラムの抽出・存在確認・集計
    3. 3. Update(データの更新)
      1. インスタンス経由で更新して save()
      2. update() メソッドで更新
    4. 4. Delete(データの削除)
      1. レコードの物理削除
      2. 論理削除(ソフトデリート)
  4. リレーション(テーブル間の関連付け)
    1. 1. 代表的なリレーションの種類と定義方法
      1. モデルでのリレーション定義例
    2. 2. リレーションデータの取得(動的プロパティとクエリメソッド)
    3. 3. 多対多の操作(attach / detach / sync)
    4. 4. N+1問題の発生原因とEagerローディング(with)
      1. N+1問題が発生する危険なコード例
      2. Eagerローディング(with)で解決
      3. Lazy Eager Loading(load)と件数カウント(withCount)
      4. 開発環境でN+1を自動検知してエラーにする設定
  5. クエリスコープ(検索条件の共通化)
    1. ローカルスコープの定義
      1. スコープの呼び出し方
  6. 属性キャスト(Casts)とアクセサ・ミューテタ
    1. 1. 属性キャスト(Casts)
    2. 2. アクセサとミューテタ(Attribute)
  7. Eloquentとクエリビルダの違い・使い分け
  8. トランザクションとデータ競合防止
    1. DB::transaction による自動ロールバック
    2. 排他ロック(lockForUpdate)
  9. 初心者がつまずきやすいエラー・トラブルと解決策
    1. 1. MassAssignmentException: Add [xxx] to fillable property
    2. 2. Call to a member function xxx() on null
    3. 3. findOrFail() で ModelNotFoundException が発生する
    4. 4. save() を呼んでも更新日時(updated_at)が変わらない
  10. よくある質問(FAQ)
    1. Q. 「Eloquent」の名前の由来・意味は何ですか?
    2. Q. Eloquentを使うとアプリの動作が重くなりますか?
    3. Q. コマンドラインから手軽にEloquentの動作確認をするには?
  11. まとめ
  12. 関連記事

Laravel Eloquentとは?基本概念と特徴

Eloquentは、Laravelに組み込まれているActiveRecordパターンのORMです。

通常、PHPからデータベースを操作するにはSQL文(SELECT * FROM users WHERE ...など)を組み立てて実行し、得られた連想配列のデータを1行ずつ処理する必要があります。しかしEloquentを使うと、データベースの「テーブル」がPHPの「クラス(モデル)」に、「行(レコード)」が「インスタンス(オブジェクト)」に対応します。

データベースの世界 Eloquent(PHP)の世界 具体例
テーブル モデルクラス users テーブル ⇔ User クラス
レコード(行) モデルのインスタンス $user = User::find(1);
カラム(列) オブジェクトのプロパティ $user->name, $user->email
テーブル間の結合(JOIN) リレーションメソッド $user->posts(ユーザーの投稿一覧)

Eloquentを使う3つの大きなメリット

  • 可読性と保守性の向上:SQLを生書きせず、Post::where('published', true)->orderBy('created_at', 'desc')->get()のように直感的なPHP構文で記述できます。
  • マスアサインメントとセキュリティ:プリペアドステートメントによるSQLインジェクション対策が自動で適用され、一括代入の制御($fillable)も標準装備されています。
  • 強力なリレーション機能:1対1、1対多、多対多などの関連データを、モデルのメソッドを定義するだけで簡単に連結・取得できます。

モデルの作成と基本設定

Eloquentを利用するには、対象テーブルに対応する「モデルクラス」を作成します。

1. Artisanコマンドでモデルを作成する

ターミナルで以下のmake:modelコマンドを実行します。テーブル作成用のマイグレーションファイルも同時に生成する場合は-mオプションを付与します。

# モデルとマイグレーションファイルを同時に作成
php artisan make:model Post -m

実行すると、以下の2つのファイルが生成されます:

  • app/Models/Post.php(モデルクラス)
  • database/migrations/2026_xx_xx_xxxxxx_create_posts_table.php(マイグレーションファイル)

2. マイグレーションでテーブルを定義する

生成されたマイグレーションファイルにカラムを定義します。

// database/migrations/2026_xx_xx_xxxxxx_create_posts_table.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
            $table->string('title');
            $table->text('body');
            $table->boolean('is_published')->default(false);
            $table->timestamps(); // created_at, updated_at を自動管理
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};

定義後、マイグレーションを実行してテーブルを作成します。

php artisan migrate

3. モデルの命名規則とカスタマイズ

Eloquentには「設定より規約(Convention over Configuration)」の原則があります。モデル名を単数形のキャメルケース(例:PostUserProfile)にすると、自動的に複数形のスネークケース(例:postsuser_profiles)のテーブル名が割り当てられます。

既存のテーブル構造や特別な要件に合わせてカスタマイズしたい場合は、モデルクラス内でプロパティを設定します。

// app/Models/Post.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    // テーブル名を明示的に指定する場合(規約と異なる場合)
    protected $table = 'blog_posts';

    // 主キーのカラム名が 'id' 以外の場合
    protected $primaryKey = 'post_id';

    // 主キーがオートインクリメントではない場合
    public $incrementing = false;

    // 主キーの型が数値以外(UUIDや文字列など)の場合
    protected $keyType = 'string';

    // created_at / updated_at の自動更新を無効化する場合
    public $timestamps = false;
}

4. マスアサインメント対策($fillable と $guarded)

フォームから送信されたリクエストデータ($request->all())をそのまま保存・更新する際、悪意あるユーザーが管理者フラグなどの不正なカラムを書き換える脆弱性を防ぐため、Laravelではマスアサインメント保護が働きます。

モデルには一括代入を許可するカラムを$fillableで指定します。詳細な使い分けはLaravel Fillableの使い方完全ガイドで詳しく解説しています。

class Post extends Model
{
    // 一括代入を許可するカラム一覧(推奨)
    protected $fillable = [
        'user_id',
        'title',
        'body',
        'is_published',
    ];
}

Eloquentの基本CRUD操作

Eloquentを使ったデータの作成(Create)、取得(Read)、更新(Update)、削除(Delete)の代表的なコード例です。

1. Create(データの作成・保存)

新規インスタンスを作成して save()

$post = new Post();
$post->user_id = 1;
$post->title = 'Laravel Eloquent入門';
$post->body = 'Eloquentの基本操作を学習中です。';
$post->is_published = true;
$post->save(); // INSERTクエリが発行される

create() メソッドで一括作成

$fillableに定義された属性を配列で渡して1行で作成・保存できます。

$post = Post::create([
    'user_id'      => 1,
    'title'        => 'Laravel Eloquent入門',
    'body'         => 'Eloquentの基本操作を学習中です。',
    'is_published' => true,
]);

firstOrCreate() と updateOrCreate()

「既存データがあれば取得、無ければ新規作成」または「既存データがあれば更新、無ければ新規作成」という処理もメソッド1つで安全に実行できます。詳しくはupdateOrCreateの使い方を参照してください。

// 条件に一致するレコードを検索し、無ければ新規登録
$post = Post::firstOrCreate(
    ['title' => 'Laravel Eloquent入門'],
    ['user_id' => 1, 'body' => '初期本文', 'is_published' => true]
);

// 条件に一致するレコードを更新、無ければ新規作成
$post = Post::updateOrCreate(
    ['title' => 'Laravel Eloquent入門'],
    ['body' => '最新の本文に更新しました。']
);

2. Read(データの取得・検索)

全件取得と主キー検索

// 全件取得(Collectionインスタンスが返る)
$posts = Post::all();

// 主キー(ID)で1件取得(見つからない場合は null)
$post = Post::find(1);

// 主キーで見つからない場合に404例外(ModelNotFoundException)を投げる
$post = Post::findOrFail(1);

findOrFail()を使用すると、コントローラー内でレコードが見つからなかった場合に自動的にHTTP 404レスポンスを返せるため実務で非常に多用されます。詳細はfindOrFailメソッドの使い方をご覧ください。

条件検索(where / orWhere / whereIn)

// 条件に一致する最初の1件を取得
$post = Post::where('is_published', true)->first();

// 条件に一致する複数件を取得
$posts = Post::where('is_published', true)
    ->where('user_id', 1)
    ->orderBy('created_at', 'desc')
    ->get();

// 複数条件のOR検索
$posts = Post::where('is_published', true)
    ->orWhere('user_id', 1)
    ->get();

// 配列内のいずれかに一致するレコードの取得(whereIn)
$posts = Post::whereIn('id', [1, 2, 3])->get();

除外条件を指定したい場合はwhereNotIn()whereNot()が使えます。詳しくはLaravel whereNot/whereNotInの使い方をご確認ください。

特定カラムの抽出・存在確認・集計

// 特定のカラムだけを配列として取り出す(pluck)
$titles = Post::where('is_published', true)->pluck('title');

// 存在確認(SELECT COUNT(*) ではなく高速なクエリを発行)
if (Post::where('user_id', 1)->exists()) {
    // 存在する時の処理
}

// 件数や集計値の取得
$count = Post::where('is_published', true)->count();
$maxId = Post::max('id');

exists()はレコードの全取得や件数カウントよりも高速に存在判定が可能です。詳細はexists()の使い方とパフォーマンスで解説しています。また特定キーの抽出にはLaravel pluckの使い方も活用できます。

3. Update(データの更新)

インスタンス経由で更新して save()

$post = Post::findOrFail(1);
$post->title = '更新されたタイトル';
$post->save(); // 変更された属性のみ UPDATE される

update() メソッドで更新

// 単一インスタンスの更新
$post = Post::findOrFail(1);
$post->update([
    'title' => '更新されたタイトル',
]);

// 条件に一致する複数レコードを一括更新(UPDATE posts SET is_published = 1 WHERE ...)
Post::where('user_id', 1)->update(['is_published' => true]);

効率的な更新パターンや注意点はLaravel Eloquentでデータ更新を効果的に行う方法にまとめています。

4. Delete(データの削除)

レコードの物理削除

// インスタンスから削除
$post = Post::findOrFail(1);
$post->delete();

// 主キーを指定して直接削除(単一または配列)
Post::destroy(1);
Post::destroy([1, 2, 3]);

// 条件を指定して一括削除
Post::where('is_published', false)->delete();

論理削除(ソフトデリート)

レコードを物理的にDBから消さず、deleted_at日時にタイムスタンプを保存して非表示にする仕組みです。

// 1. マイグレーションに softDeletes() を追加
Schema::table('posts', function (Blueprint $table) {
    $table->softDeletes();
});

// 2. モデルで SoftDeletes トレイトを使用
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Post extends Model
{
    use SoftDeletes;
}

ソフトデリートを適用すると、通常のクエリ(Post::all()など)では自動的に削除済みレコードが除外されます。

$post = Post::find(1);
$post->delete(); // deleted_at に現在時刻がセットされる

// 削除済みレコードも含めて取得
$allPosts = Post::withTrashed()->get();

// 削除済みレコードのみを取得
$deletedPosts = Post::onlyTrashed()->get();

// 削除済みレコードを復元
$post->restore();

// 完全に物理削除
$post->forceDelete();

ソフトデリートの詳しい操作法はLaravel withTrashed()の使い方と論理削除ガイドをご覧ください。

リレーション(テーブル間の関連付け)

Eloquentの最大の強みは、複数のテーブル同士のリレーションをモデルのメソッドとして直感的に定義・操作できる点です。

1. 代表的なリレーションの種類と定義方法

リレーション 関係性 メソッド名 具体例
1対1 1つのレコードが1つの関連レコードを持つ hasOne / belongsTo ユーザー ⇔ プロフィール
1対多 1つのレコードが複数の関連レコードを持つ hasMany / belongsTo ユーザー ⇔ 複数の投稿
多対多 互いに複数のレコードを持ち合う belongsToMany 投稿 ⇔ 複数のタグ(中間テーブル経由)
ポリモーフィック 1つのテーブルが複数の異なる親モデルに紐づく morphTo / morphMany コメント ⇔ 投稿または動画

モデルでのリレーション定義例

// app/Models/User.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

class User extends Model
{
    // 1対1:ユーザーは1つのプロフィールを持つ
    public function profile(): HasOne
    {
        return $this->hasOne(Profile::class);
    }

    // 1対多:ユーザーは複数の投稿を持つ
    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }
}
// app/Models/Post.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Post extends Model
{
    // 1対多の逆:投稿は1人のユーザーに所属する
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    // 多対多:投稿は複数のタグを持つ
    public function tags(): BelongsToMany
    {
        return $this->belongsToMany(Tag::class)->withTimestamps();
    }
}

2. リレーションデータの取得(動的プロパティとクエリメソッド)

定義したリレーションは、プロパティのようにアクセス(動的プロパティ)するか、メソッドとしてクエリを繋げることができます。

$user = User::findOrFail(1);

// 動的プロパティ:PostのCollectionインスタンスが返る
$posts = $user->posts;

// メソッド呼び出し:リレーションに対してさらに条件(whereなど)を追加して実行
$publishedPosts = $user->posts()
    ->where('is_published', true)
    ->orderBy('created_at', 'desc')
    ->get();

3. 多対多の操作(attach / detach / sync)

中間テーブルを介したタグなどの多対多リレーションでは、以下のメソッドで紐付けを管理します。

$post = Post::findOrFail(1);

// タグID: 1 と 2 を新規紐付け
$post->tags()->attach([1, 2]);

// タグID: 1 の紐付けを解除
$post->tags()->detach(1);

// 指定したID一覧に完全に同期(存在しない紐付けは自動削除される)
$post->tags()->sync([2, 3, 4]);

4. N+1問題の発生原因とEagerローディング(with)

リレーションで最も初心者がつまずきやすいパフォーマンスの罠が「N+1問題」です。

N+1問題が発生する危険なコード例

// 1回のクエリで100件の投稿を取得 (クエリ 1回)
$posts = Post::all();

foreach ($posts as $post) {
    // ループ内でリレーションにアクセスするたび、毎回SQLが発行される (クエリ 100回)
    echo $post->user->name;
}
// 合計クエリ数: 1 + 100 = 101回(データが増えるほど激重になる)

Eagerローディング(with)で解決

with()メソッドを使うことで、事前に必要なリレーションデータを一括取得(Eager Loading)し、クエリ数を合計2回に抑えられます。詳細はLaravel withメソッドの使い方をご確認ください。

// 投稿一覧とユーザー情報を2回のクエリでまとめて取得
$posts = Post::with('user')->get();

foreach ($posts as $post) {
    echo $post->user->name; // メモリ上のキャッシュから参照するため追加SQLは発行されない
}
// 合計クエリ数: わずか 2回

Lazy Eager Loading(load)と件数カウント(withCount)

// インスタンス取得後に後からリレーションを読み込む
$post = Post::find(1);
$post->load('user', 'tags');

// リレーションの件数だけを効率的に取得する(posts_count カラムが追加される)
$users = User::withCount('posts')->get();
foreach ($users as $user) {
    echo $user->posts_count;
}

開発環境でN+1を自動検知してエラーにする設定

Laravel 8.43以降では、開発中にN+1(Lazy Loading)が発生した際に即座に例外を投げて早期発見できる設定が備わっています。app/Providers/AppServiceProvider.phpbootメソッドに記述しておくのがベストプラクティスです。

// app/Providers/AppServiceProvider.php
use Illuminate\Database\Eloquent\Model;

public function boot(): void
{
    // 本番環境以外でLazy Loadingが行われたら例外を投げる
    Model::preventLazyLoading(! $this->app->isProduction());
}

クエリスコープ(検索条件の共通化)

よく使う検索条件(例:「公開済みの記事」「過去30日以内の投稿」など)は、モデル内に「スコープ」として定義することで、コントローラー側の記述を簡潔にし、DRY(Don’t Repeat Yourself)を保てます。

ローカルスコープの定義

Laravel 11以降では、メソッドに#[Scope]アトリビュートを付ける書き方が導入されました(従来のscopePublished($query)という命名規則も引き続き利用可能です)。

// app/Models/Post.php
namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\ScopedBy;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    // 従来記法(scopeXxx)
    public function scopePublished(Builder $query): void
    {
        $query->where('is_published', true);
    }

    // 引数を受け取るスコープ
    public function scopeOfCategory(Builder $query, int $categoryId): void
    {
        $query->where('category_id', $categoryId);
    }
}

スコープの呼び出し方

// Post::where('is_published', true)->where('category_id', 3)->get(); と同等
$posts = Post::published()
    ->ofCategory(3)
    ->latest()
    ->get();

スコープの作成コマンドやグローバルスコープの詳細はLaravelのスコープとは?ローカル・グローバルスコープの使い方を徹底解説で詳しく解説しています。

属性キャスト(Casts)とアクセサ・ミューテタ

1. 属性キャスト(Casts)

データベースに保存されたデータ(JSON文字列、0/1の整数、日付文字列など)を、PHP側の適切なデータ型(配列、真偽値、Carbonインスタンスなど)に自動変換する機能です。

Laravel 11以降は、プロパティではなくcasts()メソッドで定義する形式が推奨されています。

// app/Models/Post.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    /**
     * キャスト定義(Laravel 11+ 推奨スタイル)
     */
    protected function casts(): array
    {
        return [
            'is_published' => 'boolean',     // 0/1 を true/false に変換
            'options'      => 'array',       // JSON文字列を連想配列に変換
            'published_at' => 'datetime',    // 文字列を Carbon インスタンスに変換
            'secret_key'   => 'hashed',      // 保存時に自動ハッシュ化
        ];
    }
}

2. アクセサとミューテタ(Attribute)

データベースの値を取得・保存する際に加工を挟む機能です。Laravel 9以降はIlluminate\Database\Eloquent\Casts\Attributeクラスを使う単一構文が標準です。

// app/Models/User.php
use Illuminate\Database\Eloquent\Casts\Attribute;

class User extends Model
{
    // アクセサ & ミューテタの定義
    protected function name(): Attribute
    {
        return Attribute::make(
            get: fn (string $value) => ucfirst($value),     // 取得時に先頭を大文字化
            set: fn (string $value) => strtolower($value),   // 保存時に小文字化
        );
    }

    // 仮想属性(fullName)の定義
    protected function fullName(): Attribute
    {
        return Attribute::make(
            get: fn (mixed $value, array $attributes) =>
                "{$attributes['first_name']} {$attributes['last_name']}",
        );
    }
}

Eloquentとクエリビルダの違い・使い分け

LaravelにはEloquentのほかに、DBファサードを介してクエリを実行する「クエリビルダ」も用意されています。それぞれの特徴と使い分けを整理します。

比較項目 Eloquent ORM クエリビルダ(DB::table)
取得結果 モデルインスタンス(Model または Collection 標準オブジェクト(stdClass
リレーション hasMany, belongsTo, Eager Loadingなど標準サポート 自前でjoin()やサブクエリを組み立てる必要あり
付加機能 属性キャスト、スコープ、イベント、論理削除など豊富 最小限のSQL実行のみ
メモリ・実行速度 モデル生成のオーバーヘッドがある(数千件以上は注意) 軽量で高速(大量データの処理向き)
適した用途 通常のWebアプリ開発、CRUD処理、ビジネスロジック バッチ処理、複雑な集計クエリ、大量CSVエクスポート

クエリビルダの詳細な使い方やパフォーマンスチューニングについては、Laravel Query Builderの基本から応用およびEloquentを使わないクエリビルダ活用術も参考にしてください。

トランザクションとデータ競合防止

複数のテーブル更新を伴う処理では、途中でエラーが起きた場合にデータの不整合を防ぐためデータベーストランザクションを使用します。

DB::transaction による自動ロールバック

use Illuminate\Support\Facades\DB;

DB::transaction(function () use ($user, $amount) {
    // ユーザー残高を減算
    $user->decrement('balance', $amount);

    // 取引履歴を作成
    $user->transactions()->create([
        'amount' => $amount,
        'type'   => 'withdrawal',
    ]);
    // クロージャ内で例外がスローされた場合、自動的に全ロールバックされる
});

排他ロック(lockForUpdate)

在庫の引き当てやポイント決済など、同時に複数のリクエストが走る場面ではlockForUpdate()を使用して行ロックをかけます。

DB::transaction(function () {
    // 対象レコードを行ロックして取得
    $product = Product::where('id', 1)->lockForUpdate()->first();

    if ($product->stock > 0) {
        $product->decrement('stock', 1);
    }
});

排他ロックの実践パターンはLaravel lockForUpdate()の使い方とデータ競合防止で解説しています。

初心者がつまずきやすいエラー・トラブルと解決策

1. MassAssignmentException: Add [xxx] to fillable property

原因Post::create($request->all())などで一括代入しようとしたカラムが、モデルの$fillableに定義されていない場合に発生します。
解決策:モデルクラスの$fillable配列に対象カラム名を追加します。

2. Call to a member function xxx() on null

原因:リレーション先レコードが存在しない(nullである)のに、$post->user->nameのようにプロパティやメソッドにアクセスした場合に発生します。
解決策:PHP 8のnull安全演算子(?->)を使うか、Blade上でoptional()ヘルパーを使用します。

// null安全演算子で防御
$userName = $post->user?->name ?? 'ゲスト';

3. findOrFail() で ModelNotFoundException が発生する

原因:指定IDのレコードがDB上に存在しないためです。
解決策:Webルーティングであれば自動的にLaravelが404ページを描画してくれます。自前で存在チェックを行って処理を分岐したい場合は、find()を使ってis_null()で判定するか、exists()を使用します。

4. save() を呼んでも更新日時(updated_at)が変わらない

原因:Eloquentのsave()は、プロパティの値が前回取得時とまったく同じ場合、不要なSQLを発行しない最適化を行っています。
解決策:意図的にupdated_atを更新したい場合は、$post->touch()メソッドを呼び出します。

よくある質問(FAQ)

Q. 「Eloquent」の名前の由来・意味は何ですか?

英単語の「eloquent(エロクアント)」は「雄弁な、表現力豊かな、説得力のある」という意味の形容詞です。SQLを直接書くよりも意図が明確で、表現力豊かにデータベース操作を行えるORMという意味を込めて名付けられています。単語の詳しい語源や発音はeloquentの意味とは?Laravelとの関係やORM・クエリビルダとの違いを徹底解説で解説しています。

Q. Eloquentを使うとアプリの動作が重くなりますか?

Eloquent自体が通常のWebアプリケーションでボトルネックになることは稀です。動作が遅くなる原因の9割以上はN+1問題の放置不要な全件取得(メモリ枯渇)です。適切なEager Loading(with())の実装と、大量データ処理時のchunk()lazy()、クエリビルダの使い分けを行うことで高速に動作します。

Q. コマンドラインから手軽にEloquentの動作確認をするには?

Laravel標準の対話型シェル「Tinker」を使うのが最適です。ターミナルでphp artisan tinkerを実行すると、コントローラーやWeb画面を作らなくてもその場でUser::first()などのEloquentコードを実行・検証できます。使い方はLaravel Tinkerの使い方とデバッグ活用法を参照してください。

まとめ

LaravelのEloquent ORMは、データベース操作をPHPのオブジェクト指向に統合し、高い生産性とコードの可読性を実現してくれる中核機能です。

  • 基本の考え方:1テーブル=1モデル。make:modelで作成し、$fillableでマスアサインメントを保護する。
  • CRUD操作create(), find(), findOrFail(), where(), save(), delete() などの直感的なメソッドチェーンを活用する。
  • リレーションとN+1対策hasManybelongsToを定義し、データ取得時はwith()によるEager Loadingを徹底する。
  • 使い分け:通常のアプリケーション開発はEloquentを主軸とし、超大量データのバッチ処理や極めて複雑な集計クエリではクエリビルダを活用する。

まずは基本のCRUDとリレーションから実際にコードを動かしてみて、徐々にスコープやキャストなどの便利機能を活用していきましょう。

さらに各機能を深く学びたい方は、以下の関連解説記事もぜひ参考にしてください。

レン (Wren)

こんにちは。レンです。

Laravelのコードの森に住んでいる、小さな案内役です。
ルーティングの枝やクラスの影を歩きながら、コードの流れや仕組みを眺めています。

このサイトでは、Laravelの基本から実装のコツまで、開発で役立つポイントを静かに整理しています。
難しいことを増やすのではなく、コードの見通しが少し良くなるヒントを届けるのが役目です。

「この処理はどこに書くのがいいのか」
「Laravelではどう考えると整理できるのか」

そんな疑問に、小さなメモを残すような気持ちで記事を書いています。

コードを書いている途中で迷ったとき、
このサイトが少し立ち止まって整理できる場所になればうれしいです。

レン (Wren)をフォローする

コメント