1. 程式人生 > >laravel5.1 eloquent with 通過閉包篩選特定 field 得不到結果的問題

laravel5.1 eloquent with 通過閉包篩選特定 field 得不到結果的問題

tro 一個 ase 否則 數組 model 是你 查詢語句 兩個

(圖片有點大,可右鍵新tab查看)

User模型

class User extends Model
{
    public function profile()
    {
        return $this->hasMany(UserProfile::class);
    }
}

  

使用with查詢某個user及其的profile

User::with([‘profile‘ => function($query) {
            $query->select([‘id‘]);
        }])->find(4)->toArray()

  

上面的用法中,我們會發現,即使數據庫有記錄,sql也記錄了對應的查詢語句,但是profile關聯卻是空的,

但是加上外鍵就可以得到正確結果了:

User::with([‘profile‘ => function($query) {
            $query->select([‘id‘, ‘user_id‘]);
        }])->find(4)->toArray()

  

可以查找到正確的profile了。

這和 laravel 框架的工作方式相關,我們先看看下面的例子:

我們使用 DB::listen 方法去記錄相關的 sql 語句

這次我們不用find,用get

User::with(‘profile‘)->whereIn(‘id‘, [3, 4])
            ->get()->toArray()

  

我們查看 log 可以發現有以下語句:

select * from `tb_user` where `id` in (?, ?) [3,4] 
select * from `tb_user_profile` where `tb_user_profile`.`user_id` in (?, ?) [3,4] 

  

我們可以明顯發現,laravel 對於 user 和 user_profile 是獨立查詢的,

也就是說會得到兩個集合,一個是 User、一個是 UserProfile,

但是這並不是我們想要的結果,我們需要的結果是,只有一個 User 集合, 並且這個 User 集合裏面有 UserProfile 關聯。

但是結果就是這樣,如果是你,你會怎麽把這些數據關聯起來呢?

對了,我們定義關聯的時候不是定義了它們的關聯方式麽?

上面的 hasMany 方法默認第二第三個參數其實就是這兩個集合建立關聯的關鍵,第三個參數 user_id、第四個參數 id;

這樣一來我們就可以通過比較 UserProfile 的 user_id 和 User 裏面的 id,如果相等,則這個 UserProfile 是屬於這個 User 的,我們就把該 UserProfile 放進 User 的 profile 關聯中,最後就得到我們想要的結果了。

用xdebug證實一下我們的想法:

技術分享圖片

技術分享圖片

技術分享圖片

如我們所想的那樣,圖一的 match 方法,顧名思義就是匹配了,通過 user 模型集合和 profile 模型集合進行匹配。

圖二,也證實了我們模型建立關聯需要通過關聯中外鍵的值得想法。

圖三,是通過獲取 user 的 localkey,也就是 id 的值,來查找 $dictonary 中是否有對應的值,buildDictonary 方法會建立一個關聯數組,key 是 user_id(外鍵)的值,值是關聯的數據。這樣一樣,由於我們沒有把 user_id 也select 出來,最後得到的 $dictonary 的結構並不是預期的那樣:

技術分享圖片

其實我們本來是想要得到下面的這種:

[
  3 => xxx(UserProfile對象)       // 3 是關聯的 user_id
]

但是我們得到的卻是,所有的 UserProfile 都在一個嵌套的數組裏面了,這樣一來,下面的 getRelationValue 得到的結果自然就是空的了。

好了,總結一下,就是:laravel 先查詢主要的數據(不帶with),查詢完了之後,取出其中的 id 列數組(不一定都是id啊,只是舉個例子),將這個數組作為條件去查找關聯,有多少個關聯就會再去查找多少次,查找完關聯之後通過得到的結果的主鍵和關聯數據的外鍵比對,相等則建立關聯。

總結:在關聯篩選 field 的時候,也必須要把關聯的外鍵寫進去,否則,即使產生了正確的 sql 語句,但是它們建立不了關聯,通過 $user->profile 得到的還是一個空集合。

(對於所有關聯都有效哦)

laravel5.1 eloquent with 通過閉包篩選特定 field 得不到結果的問題