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


(圖片有點大,可右鍵新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 得到的還是一個空集合。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM