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

Yii Framework 關聯查詢與統計查詢深度解析:relations 定義、命名範圍與聯合查詢實戰

     編輯:PHP 相關知識

前言:Yii 的關聯查詢機制

Yii 1.x 的 ActiveRecord 通過 relations() 方法聲明模型間關聯,支持 BELONGS_TO、HAS_ONE、HAS_MANY、MANY_MANY 四種類型。本文深入講解統計查詢與命名範圍結合關聯查詢的高級用法,解決實際開發中「N+1 問題」與「複雜條件關聯」的痛點。

一、統計查詢:聚合數據的高效獲取

統計查詢適用於 HAS_MANY 或 MANY_MANY 關聯,用於獲取聚合信息(如評論數、平均分、標籤數),而非具體關聯對象列表。聲明方式:

class Post extends CActiveRecord {
    public function relations() {
        return array(
            // 基礎統計:評論數
            'commentCount' => array(self::STAT, 'Comment', 'post_id'),
            // 多對多統計:分類數(經過中間表)
            'categoryCount' => array(self::STAT, 'Category', 'post_category(post_id, category_id)'),
            // 條件統計:已審核評論數
            'approvedCommentCount' => array(
                self::STAT, 'Comment', 'post_id',
                'condition' => 'status=1'
            ),
            // 自定義選擇字段:平均評分
            'averageRating' => array(
                self::STAT, 'Rating', 'post_id',
                'select' => 'AVG(score)'
            ),
        );
    }
}

使用方式

$post = Post::model()->findByPk(10);
echo $post->commentCount;        // 自動執行 COUNT(*) 查詢
echo $post->averageRating;       // 自動執行 AVG(score) 查詢

// 急切加載統計(避免 N+1)
$posts = Post::model()->with('commentCount, categoryCount')->findAll();
foreach ($posts as $p) {
    echo $p->title . ': ' . $p->commentCount . ' 條評論';
}

二、命名範圍:封裝可復用的查詢條件

在模型中定義 scopes(),將常用條件封裝為鏈式調用方法:

class Post extends CActiveRecord {
    public function scopes() {
        return array(
            'published' => array('condition' => 'status=1'),
            'recent' => array('order' => 'created_at DESC', 'limit' => 10),
            'hot' => array('condition' => 'view_count > 1000', 'order' => 'view_count DESC'),
        );
    }
}

三、關聯查詢與命名範圍的組合

1. 主模型應用命名範圍

// 獲取最近發布的文章及其評論
$posts = Post::model()->published()->recent()->with('comments')->findAll();
// 等價 SQL: SELECT * FROM post WHERE status=1 ORDER BY created_at DESC LIMIT 10
// 及關聯查詢 comments

2. 關聯模型應用命名範圍(關鍵:冒號分隔)

// 獲取所有文章,但只加載「已審核」且「最近」的評論
$posts = Post::model()->with('comments:approved:recent')->findAll();
// comments 為關聯名,approved/recent 為 Comment 模型中的命名範圍

3. 在 relations() 中預設關聯範圍

class User extends CActiveRecord {
    public function relations() {
        return array(
            'posts' => array(
                self::HAS_MANY, 'Post', 'author_id',
                'with' => 'comments:approved', // 默認只加載審核通過的評論
                'order' => 'created_at DESC'
            ),
        );
    }
}
// 使用時
$user = User::model()->findByPk(1);
foreach ($user->posts as $post) {
    // $post->comments 僅包含 approved 評論
}

四、進階技巧與性能優化

場景優化方案代碼示例
大量數據統計統計查詢 + 緩存$count = Yii::app()->cache->getOrSet('post_'.$id.'_comments', fn()=>$post->commentCount, 3600);
複雜多表關聯拆分為多次查詢 + PHP 組裝避免超大 JOIN 導致臨時表/檔排序
動態關聯條件使用 on 參數而非 condition'on' => 'comment.status=1 AND comment.user_id=:uid', 'params' => [':uid'=>Yii::app()->user->id]
關聯計數顯示列表頁使用統計查詢而非加載集合with('commentCount') 代替 with('comments') 然後 count()

五、常見錯誤與避坑

  • 統計查詢用於 BELONGS_TO/HAS_ONE:無效,統計查詢僅支持多端關聯。
  • 命名範圍參數傳遞:scopes 定義中無法直接接收動態參數,需在調用時用 applyScopes() 或手動 criteria 合併。
  • with() 過深導致 SQL 爆炸:Yii 1.x 會生成多條 SQL(非 JOIN),關聯層級超過 3 層時考慮手寫 DAO/SQL。
  • STAT 關聯的 select 字段:必須為聚合函數(COUNT/SUM/AVG/MAX/MIN),否則結果不可預期。

結語

Yii 的 relations() + scopes() + with() 三位一體,構建了強大的聲明式查詢體系。掌握統計查詢替代集合加載、命名範圍封裝業務邏輯、冒號語法穿透關聯模型這三大核心技巧,能讓你在處理複雜關聯數據時既保持代碼整潔,又避免性能陷阱。建議在項目中建立關聯查詢規範文檔,統一團隊使用模式。

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