~/blog/laravel-eloquent-orm-complete-guide.md
Laravel 與後端開發 · 2025 / 08 / 15

Laravel Eloquent ORM 完整指南:搞懂 Active Record,從入門寫到效能優化

Eric — 浪花科技創辦人 / AI 架構師
Eric
浪花科技創辦人 · AI 架構師
Laravel Eloquent ORM 完整指南:搞懂 Active Record,從入門寫到效能優化
目錄 table-of-contents.md

SQL 寫得再熟,也不代表你該在專案裡手刻每一條查詢。一個欄位名稱打錯就能耗掉整個下午除錯,複雜的 JOIN 更是維護地獄的起點。Laravel 的 Eloquent ORM 用 Active Record 模式把資料表映射成物件,這篇從基本觀念一路寫到效能優化,帶你把這套工具真正用對。

幸好,我們活在一個有 Laravel 的美好時代。而 Laravel 之所以如此優雅,很大一部分要歸功於它的 ORM — Eloquent。今天,我就要帶你深入這個強大的工具,從最基礎的觀念到資深工程師必備的效能優化技巧,讓你徹底告別手寫 SQL 的痛苦,用更直觀、更具表達力的方式來操作資料庫。準備好了嗎?讓我們開始吧!

什麼是 ORM?Eloquent 又扮演什麼角色?

在我們深入 Eloquent 的細節之前,先來聊聊什麼是 ORM。ORM 的全名是 Object-Relational Mapping(物件關聯對應)。這聽起來很學術,但概念其實很簡單:它就像一個翻譯官,幫你在「物件導向的程式語言(例如 PHP)」和「關聯式資料庫(例如 MySQL)」之間建立一座橋樑。

簡單來說,ORM 讓我們可以:

  • 用操作物件的方式來操作資料庫。
  • 將資料庫中的一張資料表(Table)對應到程式中的一個類別(Class)。
  • 將資料表中的一筆紀錄(Row)對應到那個類別的一個實例(Instance/Object)。

而 Eloquent 就是 Laravel 內建的 ORM 實作,它採用了廣受歡迎的 Active Record 設計模式。這意味著每個 Model 類別不僅僅是資料結構的定義,它本身就內建了查詢、新增、修改、刪除等功能。你不需要再另外寫一個 `UserRepository` 來處理 `User` 的資料庫邏輯,`User` Model 自己就能搞定一切。這就是 Active Record 的魔力所在,它讓我們的程式碼更簡潔、更直觀。

Eloquent 基礎:CRUD 操作實戰

講了這麼多理論,是時候來點實際的了。我們假設有一個 `posts` 資料表,用來存放部落格文章。首先,我們要建立一個對應的 Model。

1. 建立 Model

你可以透過 Artisan 指令輕鬆建立一個 Model:

php artisan make:model Post

這會在 `app/Models` 目錄下建立一個 `Post.php` 檔案。一個最基本的 Model 長這樣:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;
}

Eloquent 會自動假設這個 `Post` Model 對應到 `posts` 資料表(類別名稱的蛇形、複數形式)。如果你的資料表名稱不符合這個慣例,也可以手動指定:

protected $table = 'my_posts';

2. 新增資料 (Create)

新增一筆文章資料非常簡單:

<?php
$post = new Post;
$post->title = '我的第一篇文章';
$post->content = '這是一篇關於 Eloquent 的文章...';
$post->is_published = true;
$post->save();

或者,你也可以使用 `create` 方法。不過,為了安全性,使用 `create` 方法前,你必須在 Model 中定義 `$fillable` 屬性,明確告知哪些欄位是允許被大量賦值的,這能有效防止惡意的使用者傳入非預期的欄位資料。

<?php
// 在 Post.php Model 內
protected $fillable = ['title', 'content', 'is_published'];

// 在 Controller 內
Post::create([
    'title' => '使用 Create 方法',
    'content' => '這是一種更簡潔的方式。',
    'is_published' => true,
]);

3. 查詢資料 (Read)

Eloquent 提供了非常豐富的查詢方法:

<?php
// 取得所有文章
$posts = Post::all();

// 根據主鍵 ID 尋找文章
$post = Post::find(1);

// 加上查詢條件
$publishedPosts = Post::where('is_published', true)->get();

// 排序並只取 10 筆
$latestPosts = Post::where('is_published', true)
                   ->orderBy('created_at', 'desc')
                   ->take(10)
                   ->get();

// 取得第一筆符合條件的資料
$firstPost = Post::where('is_published', true)->first();

看看這些程式碼,是不是比手寫 SQL `SELECT * FROM posts WHERE is_published = 1 ORDER BY created_at DESC LIMIT 10` 來得直觀且優雅多了?

4. 更新資料 (Update)

更新資料也很簡單。首先找到你要更新的紀錄,修改屬性後,再呼叫 `save()` 方法。

<?php
$post = Post::find(1);
$post->title = '更新後的標題';
$post->save();

如果你想一次更新多筆符合條件的紀錄,可以使用 `update` 方法:

<?php
Post::where('is_published', false)->update(['is_published' => true]);

5. 刪除資料 (Delete)

刪除資料有兩種方式,一種是找到 Model 實例後刪除,另一種是直接基於查詢條件刪除。

<?php
// 方法一:找到實例後刪除
$post = Post::find(1);
$post->delete();

// 方法二:直接刪除
Post::destroy(1);
Post::destroy([1, 2, 3]); // 刪除多筆

// 方法三:基於查詢條件刪除
Post::where('is_published', false)->delete();

關係的魔力:讓資料庫再次偉大

如果 Eloquent 只能做到 CRUD,那它不過是個語法糖。真正讓它封神的,是處理資料表之間「關係」的能力。你再也不用自己寫 `JOIN` 了!

一對多 (One To Many)

假設一個使用者 (`User`) 可以有多篇文章 (`Post`)。這就是典型的一對多關係。

<?php
// 在 User.php Model 內
public function posts()
{
    return $this->hasMany(Post::class);
}

// 在 Post.php Model 內
public function user()
{
    return $this->belongsTo(User::class);
}

定義好關係後,你可以這樣用:

<?php
// 取得某位使用者的所有文章
$user = User::find(1);
$posts = $user->posts; // 這會回傳一個包含 Post 物件的 Collection

// 取得某篇文章的作者
$post = Post::find(5);
$author = $post->user;

是不是超級直觀?完全不用去想 `foreign key` 和 `primary key` 怎麼關聯。

多對多 (Many To Many)

假設一篇文章 (`Post`) 可以有多個標籤 (`Tag`),一個標籤也可以被用在多篇文章上。這就需要一個中間表(pivot table),例如 `post_tag`。

<?php
// 在 Post.php Model 內
public function tags()
{
    return $this->belongsToMany(Tag::class);
}

// 在 Tag.php Model 內
public function posts()
{
    return $this->belongsToMany(Post::class);
}

使用起來跟一對多一樣簡單,而且 Eloquent 還提供了 `attach()`, `detach()`, `sync()` 這些方便的方法來管理中間表的紀錄。

工程師的必修課:效能優化與 N+1 問題

好了,基礎打完,現在要來談點進階的,這也是我面試新人時最愛問的問題之一。當你開心地使用 Eloquent 關係時,很容易會掉入一個叫做「N+1 查詢問題」的效能陷阱。

什麼是 N+1 問題?

想像一下這個情境:我們要顯示 100 篇文章的列表,並在每篇文章下方顯示作者的姓名。

<?php
$posts = Post::take(100)->get();

foreach ($posts as $post) {
    echo '文章標題: ' . $post->title;
    echo '作者: ' . $post->user->name; // 在這裡觸發了一次資料庫查詢!
}

你看出來問題在哪了嗎?

  • 第 1 次查詢:`SELECT * FROM posts LIMIT 100` (取得 100 篇文章)
  • 接下來的 N (100) 次查詢:在迴圈中,每次存取 `$post->user` 時,Eloquent 都會發起一次新的查詢去 `users` 資料表找作者,例如 `SELECT * FROM users WHERE id = ?`。

總共執行了 1 + 100 = 101 次查詢!這在資料量大時會造成嚴重的效能瓶頸。這就是 N+1 問題。

解決方案:預載入 (Eager Loading)

Eloquent 提供了非常優雅的解決方案:`with()` 方法。它會預先載入所有需要的關聯資料。

<?php
// 使用 with() 來預載入 user 關係
$posts = Post::with('user')->take(100)->get();

foreach ($posts as $post) {
    echo '文章標題: ' . $post->title;
    echo '作者: ' . $post->user->name; // 不會再觸發新的查詢!
}

這樣修改後,Eloquent 只會執行 2 次查詢:

  1. `SELECT * FROM posts LIMIT 100`
  2. `SELECT * FROM users WHERE id IN (1, 2, 3, ...)` (一次把所有需要的作者都撈出來)

從 101 次查詢降到 2 次!效能差異是天壤之別。記住:只要你會在迴圈中使用關聯,就一定要用 `with()` 預載入,這是一個鐵則。

結論:Eloquent 不只是工具,更是一種思維

今天我們從 Eloquent 的基本概念、CRUD 操作,一路聊到核心的「關係」以及資深工程師必備的「效能優化」。Eloquent ORM 遠不止這些,它還有 Accessors & Mutators、Query Scopes、Collections 等等強大的功能等著你去探索。

學習 Eloquent,不僅是學習一個工具,更是學習一種用物件導向思維來與資料庫互動的方式。它能讓你的程式碼更乾淨、更具可讀性,也更容易維護。當你不再需要為了拼湊 SQL 而焦頭爛額時,你才能真正專注在更重要的商業邏輯上。

當然,ORM 也不是萬靈丹。在某些極端複雜的查詢或需要極致效能的場景下,回歸 Laravel 的 Query Builder 甚至原生 SQL 也是必要的。但對於 95% 以上的應用場景,Eloquent 絕對是你最可靠的夥伴。

希望這篇完整的 Laravel Eloquent ORM 指南能幫助你打通任督二脈。如果你在開發上遇到了更複雜的架構問題,或是需要導入 Laravel 來改造現有的系統,別忘了浪花科技永遠是你最堅實的後盾。

延伸閱讀

需要專業的 Laravel 技術支援嗎?

在浪花科技,我們專注於提供高品質的 Laravel 與 WordPress 網站開發及企業系統解決方案。無論您是需要從零開始打造一個高效能的後台系統,還是對現有專案的架構與效能感到頭痛,我們的團隊都能提供專業的諮詢與協助。別讓技術問題成為您事業的絆腳石,立即聯繫我們,讓浪花科技的資深工程師團隊為您的專案保駕護航!

// FAQ

常見問題

什麼是 ORM?Laravel 的 Eloquent 又是什麼?
ORM(Object-Relational Mapping,物件關聯對應)是在物件導向程式語言與關聯式資料庫之間建立橋樑的機制,讓開發者用操作物件的方式操作資料庫,一張資料表對應一個類別、一筆紀錄對應一個實例。Eloquent 是 Laravel 內建的 ORM,採用 Active Record 設計模式,每個 Model 本身就內建查詢、新增、修改、刪除功能。
在 Laravel Eloquent 用 create() 方法新增資料前需要做什麼設定?
使用 create() 進行大量賦值前,必須在 Model 中定義 $fillable 屬性,明確列出允許被大量賦值的欄位。這能防止惡意使用者傳入非預期的欄位資料,是重要的安全防護。
如何在 Eloquent 定義一對多與多對多關係?
一對多在「一」的 Model 用 hasMany() 定義、在「多」的 Model 用 belongsTo() 定義,例如 User 有多篇 Post。多對多則在兩端 Model 都用 belongsToMany() 定義,並需要一個中間表(pivot table),Eloquent 另提供 attach()、detach()、sync() 方法管理中間表紀錄。
如何用 Eloquent 刪除資料?
有三種方式:先用 find() 取得 Model 實例再呼叫 delete();直接用 destroy() 並傳入單一或多個主鍵 ID;或以查詢條件搭配 delete(),例如 Post::where('is_published', false)->delete()。
~/roamer-tech/newsletter // FREE
// newsletter

訂閱免費電子報

把 AI 自動化、企業系統設計與 WordPress / Laravel 開發的真實案例和可直接照做的技巧,整理成電子報寄給你。只寄精選內容、不灌垃圾信,一鍵就能退訂。

$
// final.exec()

準備好讓你的網站開始為你工作了嗎?