サイトアイコン 上尾市のWEBプログラマーによるブログ

[Laravel] データを更新してもリレーション先が変更されない?

Laravel

概要

Laravelのモデルでリレーションを定義した場合、一度リレーション先のモデルを参照するとその参照が保持される。
このことはデータを参照するだけであれば問題ないが、データを更新した場合、古いリレーション先を参照することになってしまう。

※マニュアルに書かれていることではないため、もし詳しい方がいらっしゃいましたらコメントください

サンプル

例えば以下のようにusersテーブルとitemsテーブルがbelongsTo, hasOneの関係にある場合、$user->item->nameで「机」を取得することができる。
しかし、その後に$user->item_id = 2; $user->save();としても$user->item->nameは「机」のままとなってしまう。

usersテーブル

iditem_idname
11Taro
22Jiro

itemsテーブル

idname
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');
    }
}

解決方法

以下の方法が考えられる。

  1. モデルのloadメソッドでリレーションをEagerロードする。
  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();
        $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
モバイルバージョンを終了