Laravel Eloquentのデータベース操作を詳しく解説

Laravel

はじめに

Laravelは、PHPで開発された人気の高いWebアプリケーションフレームワークです。

その中でもEloquent ORMは、データベース操作を簡単かつ効率的に行うことができる優れた機能です。

Laravel Eloquentのデータベース操作には、様々な便利な機能があります。

例えば、モデルの作成や更新、関連テーブルの操作、クエリビルダの使用などがあります。

また、Laravel Eloquentは、簡潔で分かりやすいコードを書くことができるため、開発効率を大幅に向上させることができます。

さらに、Laravel Eloquentは、データベースの変更に対して柔軟に対応することができるため、開発現場で使われることが非常に多いです。

この記事では、Laravel Eloquentのデータベース操作について、初心者から上級者まで幅広く理解できるように、実際のコードを交えながら詳しく解説しています。

この記事を読むことで、Laravel Eloquentを使った効率的なデータベース操作ができるようになります。

Laravelアプリケーション開発に携わる全てのエンジニアにとって、必読の記事となることでしょう。

本記事の対象者

  • Laravel Eloquentを体系的に学習したい方
  • Laravelの学習を開始した初学者の方
  • Laravelの基礎を網羅的に固めたいと思っている方

それでは、早速見ていきましょう!

Eloquentとはそもそも何か?

一言で端的に言うと、「O/Rマッパー」です。

では、O/Rマッパーとは何かという話になりますが、オブジェクト指向言語におけるオブジェクトとリレーショナルデータベースにおけるレコードを対応付けたものです。

マッピングというのは「対応付ける」という意味があり、要するにデータベースをLaravelのオブジェクトで簡単に操作できるようにしたものということになります。

Laravelには簡単にデータベースを操作することができるメソッドがたくさん用意されています。

それでは、具体的にどのように使うのかを次の節から見ていきましょう。

レコード取得

all,get

all()メソッドはモデルのテーブルにある全てのデータを取得します。

$users = User::all();

戻り値はCollection型になります。

// 結果
Illuminate\\Database\\Eloquent\\Collection {#975 ▼ // routes/web.php:19
  #items: array:3 [▼
    0 => App\\Models\\User {#1229 ▶}
    1 => App\\Models\\User {#1230 ▶}
    2 => App\\Models\\User {#1231 ▶}
  ]
  #escapeWhenCastingToString: false
}

Collectionクラスについては別記事にて詳しく解説します。

また、get()メソッドでも同様にモデルのテーブルにある全てのデータを取得することができます。

$users = User::get();

戻り値も同じCollection型です。

// 結果
Illuminate\\Database\\Eloquent\\Collection {#975 ▼ // routes/web.php:19
  #items: array:3 [▼
    0 => App\\Models\\User {#1229 ▶}
    1 => App\\Models\\User {#1230 ▶}
    2 => App\\Models\\User {#1231 ▶}
  ]
  #escapeWhenCastingToString: false
}

では、all()とget()は何が違うのか、と思われるかもしれません。

実は、get()の場合はget()メソッドを実行する前にこの後説明するwhere()メソッドでレコードを検索してから取得することなどができます。

all()メソッドの場合はこのような使い方はできません。

なので、all()は純粋に全てのレコードを取得したい時、get()はレコードを検索する時に使うと覚えておくと良いでしょう。

where

where()メソッドはレコードをある条件に一致するレコードのみを検索、絞り込むことができます。

$user = User::where('name', '=', 'yamato')->get();

上の例の場合はユーザー名が「yamato」であるユーザーを絞り込んだ上でget()で取得しています。

// 結果
Illuminate\\Database\\Eloquent\\Collection {#975 ▼ // routes/web.php:19
  #items: array:1 [▼
    0 => App\\Models\\User {#613 ▶}
  ]
  #escapeWhenCastingToString: false
}

先ほどのget()の場合と違って、ユーザー数が1であることを確認してください。

where()の第一引数はカラム名、第二引数は条件式、第三引数は値となっています。

first

first()メソッドは最初に一致した一つのモデルのみを取得します。

$user = User::first();

戻り値はModel型になります。

// 結果
App\\Models\\User {#975 ▼ // routes/web.php:19
  ...
  #attributes: array:8 [▼
    "id" => 1
    "name" => "tarao"
    "email" => "tarao@example.com"
    "email_verified_at" => null
    "password" => "tarao1324"
    "remember_token" => null
    "created_at" => "2023-04-09 12:51:49"
    "updated_at" => "2023-04-09 12:51:49"
  ]
  ...
}

通常はwhere()で絞り込んだ後にfirst()で取得するという使われ方が多いです。

find

find()メソッドは引数のIDに合致するレコードを取得します。

$user = User::find(2);

こちらも戻り値はModel型になります。

// 結果
App\\Models\\User {#613 ▼ // routes/web.php:19
  ...
  #attributes: array:8 [▼
    "id" => 2
    "name" => "yamato"
    "email" => "yamato@example.com"
    "email_verified_at" => null
    "password" => "$2y$10$RN4GFxoiKkRiPu3RDthNme5Bmo.wtWy/.xZsr0Eo8rpvJhUPsJVLi"
    "remember_token" => null
    "created_at" => "2023-04-09 12:53:24"
    "updated_at" => "2023-04-09 12:53:24"
  ]
  ...
}

上の例だとユーザーIDが2のユーザーが取得できています。

select

select()メソッドは特定のカラムのみを取得する場合に使います。

$users = User::select('name')->get();

上の例の場合だとnameカラムのみに絞って取得しています。

// 結果
Illuminate\\Database\\Eloquent\\Collection {#975 ▼ // routes/web.php:19
  #items: array:3 [▼
    0 => App\\Models\\User {#1229 ▼
      ...
      #attributes: array:1 [▼
        "name" => "tarao"
      ]
      ...
    }
    1 => App\\Models\\User {#1230 ▶}
    2 => App\\Models\\User {#1231 ▶}
  ]
  #escapeWhenCastingToString: false
}

firstOrNew

firstOrNew()メソッドはデータがある場合は取得、ない場合は新たにインスタンスを作成するというメソッドです。

後に説明するsave()と併用されることが多いです。

$user = User::firstOrNew(['name' => '新しい名前']);
$user->save();

レコード追加

create

create()メソッドはレコードを追加するときに使うメソッドです。

$user = User::create([
    'name' => 'yamada',
    'email' => 'yamada@example.com',
    'password' => Hash::make('yamada1234')
])

戻り値はModel型になります。

データ挿入を制限するfillableやguardedが必要になります。

save

save()メソッドはレコード追加と更新を行うメソッドです。

// レコード追加
$user = new User();
$user->name = 'yamamoto';
$user->save();

// レコード更新
$user = User::find(1);
$user->email = "yamamoto@example.com";
$user->save();

戻り値はBooleanになります。

追加と更新がどちらも行えるということで、僕自身も重宝しています。

また、使っていくうちにかなり重要になってくる特徴として、save()はデータベースとの差分を見て更新しています。

つまり、データベースと差分がない場合(既にあるデータと全く同じデータを挿入するような場合)は更新自体を実行しません。

差分がある時のみ更新処理を実行しています。

insert

insert()メソッドもレコードを追加するときに使います。

他のメソッドとの違いはタイムスタンプが自動で更新されないことです。

そのため、created_atとupdated_atを指定する必要があります。

$user = User::insert([
	'name' => '名前',
	'created_at' => now(),
	'updated_at' => now()
]);

戻り値はBooleanになります。

僕の肌感ですが、insertメソッドを実際の開発現場で使うことはあまりなく、ほとんどがsave()メソッドを使っている印象があります。

firstOrCreate

firstOrCreate()メソッドはデータがあれば取得、なければデータを追加するメソッドです。

$user = User::firstOrCreate(
    ['name' => 'ユーザー名'],
    ['email' => 'メールアドレス']
)

レコード更新

update

update()メソッドはデータを更新したい時に使うメソッドです。

User::where('id', '<', 5)->update([ 'name' => '新しい名前' ]);

戻り値は更新したレコード数になります。

重要な点として、update()する前にwhere()で更新対象のレコードを指定していることです。

これがないとエラーになってしまうので気をつけましょう。

上の例のように複数モデルを一括で更新することも可能です。

また、update()もタイムスタンプが自動更新されないといったデメリットがあります。

更新についても個人的にはsave()メソッドの方がおすすめです。

updateOrCreate

updateOrCreate()メソッドは既にデータが存在していれば更新し、なければデータを追加します。

$user = User::updateOrCreate(
	['name' => 'satou'],
	['name' => 'suzuki']
);

レコード削除

delete

delete()メソッドはデータを削除するときに使うメソッドです。

// 全レコードを削除
User::delete();

// 特定のレコードを削除
User::where('id', '=', 2)->delete();

戻り値は削除したレコード数になります。

truncate

truncate()メソッドは前レコードを削除するメソッドです。

delete()との違いはtruncate()はインクリメントもリセットすることです。

User::truncate();

destroy

destroy()メソッドはIDを指定してレコードを削除するメソッドです。

// 単体削除
User::destroy(1);

// 複数削除
User::destroy([1,2]);

IDを配列で渡すことで、複数削除も可能です。

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

データの削除の方式には2種類あります。

物理削除と論理削除です。

物理削除はデータそのものを消すので後から復活させることはできません。

論理削除はデータを消したことにするだけなので、後から復活できます。

Laravelのデフォルトではデータを削除した場合は物理削除になります。

しかし、Laravelにはデータを論理削除する方法が用意されています。

その具体的な方法を見ていきましょう!

ソフトデリートの方法

まず、マイグレーションファイル内にsoftDeletes()を指定します。

Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->rememberToken();
        $table->softDeletes(); // ここ。
    $table->timestamps();
});

こちらをマイグレートします。

php artisan migrate

そうすると、deleted_atカラムが追加されます。

次に、モデル内にSoftDeletesトレイトを追加します。

<?php

namespace App\\Models;

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

class User extends Model
{
    use SoftDeletes;
}

これで設定は完了です。

以降はデータを削除した場合にレコードは削除されず、deleted_atカラムに削除した日時が入るようになります。

特定のインスタンスがソフトデリートされているか確認する場合はtrashed()メソッドを使用することができます。

if ($user->trashed()) {
	//
}

ソフトデリートしたモデルを復元する場合は、restoreメソッドを呼び出します。

$user->restore();

モデルを完全に削除する場合はforceDelete()メソッドを使用します。

$user->forceDelete();

ソフトデリートしたデータを含めて取得したい場合はwithTrashed()メソッドを使用できます。

$user = User::withTrashed()
    ->where('id', 1)
    ->get();

ソフトデリートしたモデルのみを取得したい場合はonlyTrashed()メソッドを使用することができます。

$user = User::withTrashed()
  ->get();

DBパフォーマンス最適化

Laravel Eloquentの基本的な使い方がわかったら、次はDBパフォーマンスを意識したコードの書き方を学ぶ必要が出てきます。

一般に、DBパフォーマンス最適化の方法は以下が挙げられるかと思います。

  • SQL発行回数を減らす
  • キャッシュを可能な限り活用する
  • 無駄なデータを取得しない
  • chunk()メソッドで処理するブロックを小分けにする

パフォーマンスの最適化は処理速度だけではなく、PHPメモリを枯渇しないようなコードの書き方も含めます。

SQL発行回数を減らす

まずはSQL発行回数をできるだけ減らすことを考えましょう。

SQLの有名な問題にN+1問題というものがあります。

これは、具体的には以下のようにSQLを発行していることを指しています。

  • N件のレコードを持つテーブルを読みだすのに1回
  • リレーション先のテーブルから各レコードにつきデータを1件ずつ読み出すのに計N回

無駄なSQLを大量に発行してしまっている状態なので、対策する必要があります。

Laravelではwith()メソッドという1回のSQLでリレーション先のテーブルデータも付属して取得する方法があります。

まずはこちらを積極的に活用するといいでしょう。

$user = User::select([
    'id',
    'name',
    'created_at',
])->with(['posts' => function ($query) {
    $query->select(['id', 'title', 'body',]);
}])
->where('id', '=', 1)
->first();

キャッシュを可能な限り活用する

Laravelのキャッシュ機能は取得に時間がかかるような重い処理を実行する際に活用します。

取得したデータを一時置き場のようなところに置いておきます。

同じデータにアクセスした際に一時置き場から取り出すことができるので、DBに負荷がかからず、レスポンスを早く返すことができます。

Laravelでは通常Redisというキーと値を保存しておくDBよりも小さな保存領域を活用することが多いです。

また別記事で紹介しようと思いますが、Redisを活用して処理のかたまりをキャッシュしておき、保存した処理をバックグラウンドで実行するというようなことも可能です。

Laravelを使いこなせてきたらこの辺りを学習することをおすすめします。

無駄なデータを取得しない

できる限り無駄なデータは取得しないように心がけましょう。

例えば、本記事で紹介したselect()メソッドを使用すれば、欲しいカラムに絞ってデータを取得するようなことが可能になります。

また、繰り返し分でデータを取得するのではなく、SQLで一括でデータを取得できないかなどはコードを書く際に念頭に置いておくべきです。

このように、過不足なくデータを取得できるように気をつけましょう。

chunk()メソッドで処理するブロックを小分けにする

Laravelにはある処理を小分けにして処理する方法が用意されています。

以下はchunk()メソッドを使ってデータを200件ずつ処理した例です。

User::chunk(200, function (users) {
	foreach ($users as $user) {
		//
	}
})

小分けにすることで、DBに一気に大量のデータが押し寄せてくるというようなことはなくなり、負荷が減ります。

一度に大量に処理を走らせなければならない重たい処理を書く時には積極的に活用していきましょう。

最後に

今回の記事では、Laravel Eloquentを使ったデータベース操作について詳しく解説してきました。

Eloquentは、Laravelフレームワークが提供するORM(Object Relational Mapping)の一種で、データベースの操作をオブジェクト指向的に扱うことができます。

Eloquentを使うことで、SQL文を書かなくても簡単にデータベースの操作ができるため、開発効率を大幅に向上させることができます。

また、Eloquentが提供する機能により、データの取得や更新が簡単に行えるため、アプリケーションの開発において非常に便利です。

今回の記事を参考に、Eloquentを使ったデータベース操作について学び、自分のプロジェクトで活用してみてください。

より高度な操作を学びたい場合は、公式ドキュメントや書籍などの情報源もぜひ参考にしてみてください。

ではでは😆

コメント

タイトルとURLをコピーしました