首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

Yii 2.0 關聯查詢深度解析:從關係定義到急切/延遲加載實戰

     編輯:PHP 綜合知識

Yii 的 Active Record (AR) 關聯查詢是框架最強大的特性之一,能將多表關係映射為物件屬性鏈式訪問。本文系統梳理四種關係類型、配置語法、加載策略、條件控制與靜態查詢,並附最佳實踐建議。

四大關係類型與對應常量

關係常量數據庫關係典型場景
屬於self::BELONGS_TO多對一Post → User (author_id)
有多個self::HAS_MANY一對多User → Post (author_id)
有一個self::HAS_ONE一對一User → Profile (owner_id)
多對多self::MANY_MANY多對多(需中間表)Post ↔ Category (post_category)

關係配置:覆寫 relations() 方法

public function relations() {
    return array(
        '關係名' => array(關係常量, '關聯模型類', '外鍵', '額外選項...'),
    );
}

實例:Post 與 User

// Post.php
'user' => array(self::BELONGS_TO, 'User', 'author_id'),

// User.php
'posts' => array(self::HAS_MANY, 'Post', 'author_id'),
'profile' => array(self::HAS_ONE, 'Profile', 'owner_id'),

多對多:Post ↔ Category

// Post.php
'categories' => array(self::MANY_MANY, 'Category', 'post_category(post_id, category_id)'),

// Category.php
'posts' => array(self::MANY_MANY, 'Post', 'post_category(category_id, post_id)'),

關鍵:中間表名在前,外鍵順序與「本模型在前、關聯模型在後」對應。

使用方式:延遲加載 vs 急切加載

1. 延遲加載(預設)

$post = Post::model()->findByPk(10);
$author = $post->user;        // 自動執行 SELECT * FROM user WHERE id=...
$posts = $user->posts;        // SELECT * FROM post WHERE author_id=...

優點:代碼簡潔。缺點:N+1 問題,遍歷列表時產生大量 SQL。

2. 急切加載 with()

$posts = Post::model()->with('user')->findAll(); // 1 條 JOIN 查詢
foreach ($posts as $post) {
    echo $post->user->name; // 無額外查詢
}

支援巢狀:with('user.profile')、多關係:with('user', 'categories')。

帶參數的關係配置(條件、排序、選欄等)

'doingOutsources' => array(
    self::MANY_MANY, 'Outsource', 'outsource_user(user_id, outsource_id)',
    'condition' => "doingOutsources.status_id IN (" . Status::ASSIGNED . ", " . Status::STARTED . ")",
    'order'     => 'doingOutsources.created_at DESC',
    'select'    => 'id, title, status_id',
    'limit'     => 10,           // 僅延遲加載生效
    'offset'    => 0,
    'with'      => 'categories', // 巢狀急切加載
    'together'  => true,         // 強制單條 SQL(MANY_MANY/HAS_MANY)
    'alias'     => 'doingO',     // 表別名
    'on'        => 'doingO.type=1', // JOIN ON 條件(覆蓋外鍵)
    'index'     => 'id',         // 結果陣列鍵名
    'params'    => array(':uid'=>Yii::app()->user->id),
    'group'     => 'doingO.status_id',
    'having'    => 'COUNT(*) > 1',
),

靜態查詢 self::STAT:聚合計數不載入模型

'commentCount' => array(self::STAT, 'Comment', 'post_id'),
'categoryCount' => array(self::STAT, 'Category', 'post_category(post_id, category_id)'),
// 帶條件
'doingOutsourceCount' => array(
    self::STAT, 'Outsource', 'outsource_user(user_id, outsource_id)',
    'condition' => "outsource.status_id IN (" . Status::ASSIGNED . ", " . Status::STARTED . ")"
),

用法:

$post->commentCount; // 延遲
$posts = Post::model()->with('commentCount', 'categoryCount')->findAll(); // 急切

最佳實踐建議

  • 列表頁**必須**使用 with() 急切加載,避免 N+1
  • 多對多關係只需在**需要查詢的一方**定義
  • 靜態查詢適合「顯示計數但不需要模型詳情」場景
  • 複雜條件優先用 CDbCriteria + with(),而非在關係定義寫死
  • 關閉不需要的關係:Post::model()->with(array('user'=>false))->findAll()

熟練掌握 Yii 關聯查詢,能讓數據庫操作代碼減少 80% 以上,同時保持極高的可讀性與性能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved