Laravel - 完全杜絕 N+1 issue 的可能

# 前言

有使用 Laravel 的朋友相信對 Eager loading 以及 Lazy loading 都不陌生
有時專案很趕, API 一次要開很多支, 常常沒注意到就產生了 Lazy loading N+1 issue
本篇文章提供一個概念性方法來完全的杜絕 N+1 issue, 不過各位朋友啊, 這只是個概念, 沒有真正實作於 Production 環境, 如果朋友不怕死你可以試試, 但出事千萬別找我啊!



# 建立新的 base model

首先, 在 app 資料夾底下新增 Model 檔案, 內容如下:

<?php

namespace App;

use Exception;
use Illuminate\Database\Eloquent\Model as Eloquent;

class Model extends Eloquent
{
public function getRelationshipFromMethod($name)
{
// 呼叫的 model
$class = get_class($this);
// $name = 被呼叫的 relation
throw new Exception("Lazy-loading relationships is not allowed ($class::$name).");
}
}

主要是因為 getRelationshipFromMethod 會在 Lazy loading 之前被呼叫, 因此我們只要覆寫了這個 method, 並新增 throw Exception 的邏輯, 那當使用 lazy loading 時就會噴錯, 噴錯你就不能繼續開發, 不能繼續開發你就會想辦法解決 N+1 issue 啦!



# 變更 extended model

以下為 example code, 假設我們有個 Customer model 想要套用以上設定, 就要 extend 我們上面新增的 model, 而因原本的 Eloquent Model

<?php

namespace App;
// 將原本這邊會 use Eloquent\Model 拿掉, 就會 extend 同 namespace 下面我們上面新增的 model 啦!

class Customer extends Model
{
public function salesRep()
{
return $this->belongsTo(User::class);
}
}


# 驗證

驗證的時候到了, 將下面的 with() comment 掉, 就會噴錯了

<?php

namespace App\Http\Controllers;

use App\Customer;

class CustomersController extends Controller
{
public function index()
{
$customers = Customer::query()
// ->with('salesRep')
->orderBy('name')
->paginate();

return view('customers', ['customers' => $customers]);
}
}


# 結論

再次重申, 這我也沒用在 Production 過, 想嘗試的朋友自己追一下 source code 再三思啊!

Selection Sort (選擇排序法) In PHP Laravel - Eloquent ORM - Mutators

留言

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×