iT邦幫忙

2023 iThome 鐵人賽

DAY 18
0
自我挑戰組

我推的Laravel系列 第 18

【Day-17】我推的Laravel-進階篇-Model Relation & N+1 Query問題

  • 分享至 

  • xImage
  •  

簡介

前面介紹過Model、Repository,或許讀者會好奇這兩者的差異
首先,當然Repository不是Laravel預設有的,而實際上,也是有分 用/不用Service/Repository派
支持派認為,Service/Repository可以做到分層清楚、重用性高
反對派認為,Model可以用scope、trait達到同樣效果
不過這些都是題外話

實作

今天一樣用先前使用Post的例子
還記得在創建Post有預留一個user_id嗎

假設今天的登入的user_id = 1
PS:可以透過以下mysql語法所有post的user_id

UPDATE posts
SET user_id = 1;

接著可以新增user

INSERT INTO `ithelp`.`users` (`id`, `name`, `email`, `email_verified_at`, `password`) VALUES ('1', 'ryan', 'ryan@test.com', '2023-10-02 19:50:45', 'none');

以上資料都是測試用

接著在Model加入Relation
app\Models\Post.php

public function user(): BelongsTo
{
    return $this->belongsTo(User::class);
}

app\Http\Controllers\PostController.php

public function index(PostService $postService) {
    $posts = Post::with('user')->get();
    return response()->json(['data' => $posts], 200);
}

Postman測試:
https://ithelp.ithome.com.tw/upload/images/20231002/20163286Y0wVdxupbi.png
可以看到每個Post很方便又快速的取得了發文者的資料

當然如果你要取得user的全部發文也可以
app\Models\User.php

public function posts(): HasMany
{
    return $this->hasMany(Post::class);
}

在你需要的地方

User::with('posts')->get();

belongsTo、hasMany之外還有belongTo、hasOne等等
這取決於兩表之前的關係是一對多,誰一誰多
這個例子是Post屬於User,而User可以有多Post,可以以這個例子去思考你所需要的關係
其他的寫法

N+1 Query 問題

今天的例子剛好解決N+1 Query的問題

Post::with('user') 在 Laravel 中是一種解決 N+1 查詢問題的方法,它使用 Eager Loading(貪婪加載)來一次性加載所有需要的關聯數據,而不是在後續的迴圈中進行單獨的查詢。

以下的代碼則會造成N+1 Query 問題

$posts = Post::all(); // query 1次
foreach ($posts as $post) {
    $user = User::find($post->user_id); // query N次
    ...
}

看到以上的程式可以發現,foreach因為跑了$posts的數量N次
$posts也是一次query,所以是N+1問題

而Post::with('user')則是以(類似)

SELECT * FROM posts;

SELECT * FROM users WHERE id IN (?, ?, ?, ...);

只需要兩次query就可以達到,複雜度下降一個維度,減少伺服器、mysql負擔

總結

除了relation另外還有scope、trait等等,可以查看官網
你要把之前Repository邏輯寫在Model層也是可以,筆者之前經歷過中大型專案也有這麼做的
而筆者認為,Model有自帶的定位和方法,加入不是用這些方法有點像畫蛇添足

總而言之,今天用Model Realation的例子帶給讀者了解到Model的其中一種用法,也許能讓你了解到Model的定位及定義


上一篇
【Day-16】我推的Laravel-進階篇-Interface & Contract Pattern
下一篇
【Day-18】我推的Laravel-進階篇-Extend & Implement
系列文
我推的Laravel31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言