yii2 ActiveRecord多表關聯以及多表關聯搜索的實現

做者:白狼 出處:http://www.manks.top/yii2_many_ar_relation_search.html 本文版權歸做者,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。php

一個老生常談的問題。最近經過羣裏的反饋,以爲不少人仍是沒有去理解這個問題。今天把這個問題講明白了,看看yii2 ActiveRecord是怎麼個多表關聯以及如何去優化這個關聯。html

場景需求:sql

假設咱們有一張用戶表user和一張用戶渠道表auth,兩張數據表經過user.id和auth.uid進行一對一關聯。現須要在user列表展現auth表的來源渠道source,且該渠道可搜索。yii2

首先咱們先經過gii生成user和auth系列相關的model和操做。此處不作詳細說明,有關gii的操做可參考xxxyii

我看繼續看重要的幾個操做步驟:函數

一、找到user表對應的AR模型類 common\models\User.php,在該類文件中進行關聯auth表優化

/**
 *  關聯auth表
 */
public function getAuth()
{
    // hasOne要求返回兩個參數 第一個參數是關聯表的類名 第二個參數是兩張表的關聯關係 
    // 這裏uid是auth表關聯id, 關聯user表的uid id是當前模型的主鍵id
    return $this->hasOne(common\models\Auth::className(), ['uid' => 'id']);
}

設置好了以後,並不表明兩張數據表自動進行關聯了!咱們訪問user列表頁(該列表頁採用gii生成,目前咱們沒操做過),經過debug查看Database Queries不難發現,實際中的query並無進行關聯auth表網站

二、在gridview中添加關聯表的來源渠道字段sourceui

<?= GridView::widget([
    // other codes
    'columns' => [
        // other columns
        'auth.source',
    ]
]); ?>

有同窗感受疑問了,上面不是說了沒進行關聯嗎,這個怎麼能夠直接使用auth.source?this

先別急,此時咱們打開debug看看實際的query。

咱們會發現有不少相似 select * from auth where uid = xxx;之類的操做,若是你的分頁默認20條數據時,會有20個相似的query。

咱們先搞明白髮生了什麼?

實際上這屬於php的基礎知識了。讀取和寫入對象的一個不存在的成員變量時, __get() __set() 魔術函數會被自動調用。yii也是利用了這一點對其進行了實現!

該操做跟大部分人在gridview中封裝方法獲取關聯表數據幾乎一致,可是!20條sql的查詢明顯增長了衆多的開銷。若是這裏是left join操做多好!

三、優化sql

咱們須要優化的是:

20條sql變1條sql

只獲取關聯表須要的字段

有同窗要嚷嚷了,這裏是yii自帶的操做,怎麼優化?咱們回到數據源的獲取上,發現user列表的數據是經過userSearch model的search方法提供的。

也就是說咱們的數據查詢實際上就沒有去進行關聯表查詢!既然如此,咱們就在UserSearch加上關聯查詢

$query = User::find();
$query->joinWith(['auth']);
$query->select("user.*, auth.source");

咱們再來刷新下user列表頁,而後經過debug分析發現有兩條sql引發了咱們的注意

SELECT `user`.*, `auth`.`source` FROM `user` LEFT JOIN `auth` ON `user`.`id` = `auth`.`uid` LIMIT 20
SELECT * FROM `auth` WHERE `user_id` IN (20個uid);

也就是說我麼已經達到了優化sql的目的,經過debug分析發現,DB的查詢時間少了不少。

四、關聯表字段增長查詢

gridview中的搜索模型也是經過searchModel實現的,該模型經過rules控制着哪一個字段可搜索,哪一個字段不可搜索。

咱們如今須要增長關聯表的source可搜索,所以咱們在searchModel中定義一個屬性source且添加到rules中

public $source;
public function rules()
{
    return [
    // other rules
        ['source', 'safe'],
    ];
}

接着咱們把gridview中的auth.source修改一下

// 'auth.source',
[
    'attribute' => 'source',
    'value' => 'auth.source',
    'label' => '渠道來源',
],

到這裏咱們界面上是ok的,要實現程序上的搜索還差一步,咱們在數據源獲取的地方加上新增的source條件便可

$query->andFilterWhere([
    // other params
    'auth.source' => $this->source,
]);

[考慮目前國內網站大部分採集文章十分頻繁,更有甚者不註明原文出處,原做者更但願看客們查看原文,以防有任何問題不能更新全部文章,避免誤導!]

查看原文

相關文章
相關標籤/搜索