概要
Laravelのモデルでリレーションを定義した場合、一度リレーション先のモデルを参照するとその参照が保持される。
このことはデータを参照するだけであれば問題ないが、データを更新した場合、古いリレーション先を参照することになってしまう。
※マニュアルに書かれていることではないため、もし詳しい方がいらっしゃいましたらコメントください
サンプル
例えば以下のようにusersテーブルとitemsテーブルがbelongsTo, hasOneの関係にある場合、$user->item->nameで「机」を取得することができる。
しかし、その後に$user->item_id = 2; $user->save();としても$user->item->nameは「机」のままとなってしまう。
usersテーブル
| id | item_id | name |
|---|---|---|
| 1 | 1 | Taro |
| 2 | 2 | Jiro |
itemsテーブル
| id | name |
|---|---|
| 1 | 机 |
| 2 | イス |
サンプル1
<?php
namespace App\Http\Controllers;
use Illuminate\View\View;
class IndexController extends Controller
{
public function index(Request $request): View
{
$user = User::find(1);
echo $user->item->name; // 机
$user->item_id = 2;
$user->save();
echo $user->item->name; // 机 ※イスではない
return view('index.index');
}
}
サンプル2(条件式で参照)
<?php
namespace App\Http\Controllers;
use Illuminate\View\View;
class IndexController extends Controller
{
public function index(Request $request): View
{
$user = User::find(1);
if ($user->item->name !== 2) { // ここで机を参照しているので、保持される
$user->item_id = 2;
$user->save();
echo $user->item->name; // 机 ※イスではない
}
return view('index.index');
}
}解決方法
以下の方法が考えられる。
- モデルのloadメソッドでリレーションをEagerロードする。
- リレーション先のモデルを参照するのではなく、外部キーとなっているカラムの値を参照する。
サンプル1
<?php
namespace App\Http\Controllers;
use Illuminate\View\View;
class IndexController extends Controller
{
public function index(Request $request): View
{
$user = User::find(1);
echo $user->item->name; // 机
$user->item_id = 2;
$user->save();
$user->load('item'); // Eagerロード
echo $user->item->name; // イス
return view('index.index');
}
}サンプル2
<?php
namespace App\Http\Controllers;
use Illuminate\View\View;
class IndexController extends Controller
{
public function index(Request $request): View
{
$user = User::find(1);
if ($user->item_id !== 2) { // 外部キーを参照
$user->item_id = 2;
$user->save();
echo $user->item->name; // イス
}
return view('index.index');
}
}参考サイト
Attention Required! | Cloudflare


コメント