はじめに
(サンプルのバージョンは 5.5 で書いてます)
Laravelって便利。リレーションだって簡単に貼れます。
しかし、書き方によって予期しない挙動したので備忘録として残します。
実際にやってみた
まずサンプルとして、ユーザ情報を扱うテーブルと、トレーニング情報を扱うテーブルを用意。
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(64) NOT NULL COMMENT '名前',
`deleted_at` datetime DEFAULT NULL COMMENT '削除日時',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='ユーザ';
CREATE TABLE `trainings` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`trained_user_id` int(10) unsigned NOT NULL COMMENT 'トレーニング者',
`summary` varchar(255) NOT NULL COMMENT '概要',
`deleted_at` datetime DEFAULT NULL COMMENT '削除日時',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='トレーニング';
トレーニング情報と一緒に、トレーニング者のユーザ名を取得したいとき、
Modelクラスでこのように関数を設置し、belongsToでリレーションを貼っておくと、
Training情報を取得した時にも trained_user関数 を呼び出しただけで users 情報を取得できます。
Training.php
use Illuminate\Database\Eloquent\Model;
/**
* Class Training
*/
class Training extends Model
{
public function trained_user()
{
return $this->belongsTo(User::class);
}
}
$trainings = Training::all();
$trainings[0]->trained_user->name; // トレーニング者の名前が取れる
でも、やったね!と思ってクエリログを見ると愕然します...
select * from `trainings` where `trainings`.`deleted_at` is null
select * from `users` where `users`.`id` = '1' and `users`.`deleted_at` is null limit 1
select * from `users` where `users`.`id` = '2' and `users`.`deleted_at` is null limit 1
select * from `users` where `users`.`id` = '3' and `users`.`deleted_at` is null limit 1
みてください、・・・ユーザ分毎回SQL投げてる;;;;
めっちゃパフォーマンス悪い;;;;
反省して書き直し。
$trainings = Training::with(['trained_user'])->get(); // trained_user を設定する
$trainings[0]->trained_user->name; // 同様にトレーニング者の名前が取れる
クエリログは・・・
select * from `trainings` where `trainings`.`deleted_at` is null
select * from `users` where `users`.`id` in ('1', '2', '3') and `users`.`deleted_at` is null
期待どおりの結果になりました!
というわけで、リレーション貼ってる時は気をつけましょう〜