(圖片有點大,可右鍵新tab查看)php
User模型laravel
class User extends Model { public function profile() { return $this->hasMany(UserProfile::class); } }
使用with查詢某個user及其的profilesql
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 框架的工做方式相關,咱們先看看下面的例子:ui
咱們使用 DB::listen 方法去記錄相關的 sql 語句this
此次咱們不用find,用getspa
User::with('profile')->whereIn('id', [3, 4]) ->get()->toArray()
咱們查看 log 能夠發現有如下語句:debug
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 獲得的仍是一個空集合。
(對於全部關聯都有效哦)