ThinkPHP 的關聯模型(RelationModel)提供了優雅的方式處理資料表間的關聯關係,支援四種核心關聯類型:HAS_ONE、BELONGS_TO、HAS_MANY、MANY_TO_MANY。本文系統整理關聯定義語法、常用屬性參數,並示範關聯查詢、寫入、更新、刪除的完整操作流程。
| 關聯類型 | 關係描述 | 典型場景 |
|---|---|---|
| HAS_ONE | 一對一(擁有) | User → Profile |
| BELONGS_TO | 一對一(屬於) | User → Dept(用戶屬於部門) |
| HAS_MANY | 一對多 | User → Articles(用戶擁有多篇文章) |
| MANY_TO_MANY | 多對多 | User ↔ Group(透過中間表 think_group_user) |
所有關聯定義集中在模型類的 $_link 成員變數中,模型需繼承 RelationModel:
class UserModel extends RelationModel {
protected $_link = array(
'關聯名稱' => array(
'mapping_type' => HAS_ONE, // 關聯類型(必填)
'class_name' => 'Profile', // 關聯模型類名
'mapping_name' => 'profile', // 映射名稱(查詢結果鍵名)
'foreign_key' => 'user_id', // 外鍵名稱
'condition' => 'status=1', // 關聯條件
'mapping_fields'=> 'id,name', // 要查詢的字段
'as_fields' => 'name:profile_name', // 字段映射到主模型
// ... 更多屬性見下文
),
);
}
'Profile' => array(
'mapping_type' => HAS_ONE,
'class_name' => 'Profile',
'foreign_key' => 'user_id', // Profile 表中的外鍵
'mapping_name' => 'profile',
'mapping_fields'=> 'email,nickname',
'as_fields' => 'nickname:profile_nickname',
)
'Dept' => array(
'mapping_type' => BELONGS_TO,
'class_name' => 'Dept',
'foreign_key' => 'dept_id', // User 表中的外鍵
'mapping_name' => 'dept',
'parent_key' => 'id', // 自引用關聯時使用
)
'Article' => array(
'mapping_type' => HAS_MANY,
'class_name' => 'Article',
'foreign_key' => 'user_id',
'mapping_name' => 'articles',
'mapping_order' => 'create_time DESC',
'mapping_limit' => '10',
'mapping_fields' => 'id,title,create_time',
)
'Group' => array(
'mapping_type' => MANY_TO_MANY,
'class_name' => 'Group',
'mapping_name' => 'groups',
'foreign_key' => 'user_id', // 中間表中的用戶外鍵
'relation_foreign_key' => 'group_id', // 中間表中的群組外鍵
'relation_table' => 'think_group_user', // 中間表名
'mapping_order' => 'id DESC',
'mapping_limit' => '20',
)
使用 relation(true) 啟用所有定義的關聯,或傳入陣列指定部分關聯:
$User = D('User');
// 1. 載入所有關聯
$user = $User->relation(true)->find(1);
// 2. 僅載入指定關聯
$user = $User->relation('Profile,Article')->find(1);
// 結果範例
array(
'id' => 1,
'account' => 'ThinkPHP',
'password' => '123456',
'Profile' => array('email' => 'liu21st@gmail.com', 'nickname' => '流年'),
'Article' => array( /* 文章列表 */ ),
)
$User = D('User');
$data = array(
'account' => 'ThinkPHP',
'password' => '123456',
'Profile' => array(
'email' => 'liu21st@gmail.com',
'nickname' => '流年',
),
);
$result = $User->relation(true)->add($data);
// 會自動寫入 user 表與 profile 表,並正確關聯外鍵
$data = array(
'account' => 'ThinkPHP',
'password' => '123456',
'Profile' => array(
'email' => 'liu21st@gmail.com',
'nickname' => '流年',
),
);
$result = $User->relation(true)->where('id=3')->save($data);
// 刪除用戶時,根據關聯定義可級聯刪除關聯資料
$result = $User->relation(true)->delete('3');
注意:級聯刪除行為取決於關聯類型與資料庫外鍵約束,建議在關聯定義中明確 condition 或配合資料庫層面的 ON DELETE CASCADE。
$_link 鍵名)建議使用駝峰式,與模型類名一致。relation(true) 載入所有關聯,造成 N+1 查詢問題;改用 relation('Profile') 指定所需關聯。mapping_fields 只選取必要欄位,減少資料傳輸量。掌握 ThinkPHP 關聯模型,能讓資料庫操作代碼更符合領域模型思維,減少手動 Join 與資料組裝的樣板代碼,提升開發效率與可維護性。