<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ### 2018 年 11 月 24 日 發布 ## 前言 ThinkPHP5的模型關聯是按照面向對象的開發思想重構的,和`3.2`時代的關聯模型實現和用法完全不同。因此,要掌握`5.*`的模型關聯,必須要有面向對象的思想意識,重新認識新版的模型關聯,這是理解和掌握模型關聯的關鍵。 掌握模型關聯的關鍵是掌握關聯的定義和查詢,關聯的寫入完全可以用模型自身的寫入來完成,而不要依賴關聯寫入(只有某些特殊的關聯才需要單獨的關聯寫入)。 本文主要為大家盡量淺顯的講解下模型關聯的查詢操作和注意事項,主要指導開發者打通模型關聯的使用障礙和恐懼,從而可以漸入佳境的學習模型關聯。由于模型關聯涉及的面比較廣,沒法做到面面俱到,因此本文內容不做太多深入,以免形成長篇累牘,更加詳細的模型關聯用法建議參考官方的《[掌握ThinkPHP5.0數據庫和模型](http://www.hmoore.net/thinkphp/master-database-and-model)》教程中的「[第八章:模型關聯](http://www.hmoore.net/thinkphp/master-database-and-model/265559)」。 ## 基本用法 關聯定義是第一步,如果沒法正確的完成關聯定義,你將不得其門而入。但其實關聯的定義方法本身很簡單,難點在于判斷你的業務操作應該使用什么關聯關系,而具體表之間的關系其實在做數據庫架構設計的時候已經明確了的。 關聯關系通常有一個參照模型,這個參照模型我們一般稱為主模型(或者當前模型),關聯關系對應的模型就是關聯模型,關聯關系是指定義在主模型中的關聯關系,有些關聯關系還會設計到一個中間表的概念,但中間表不一定需要存在具體的模型。關聯模型本身也是一個普通的獨立模型,具備模型的所有功能。兩個模型之間的關聯關系就是通過關聯方法來定義的。 目前已經支持的關聯關系如下: |模型方法|關聯類型| |---|---| |`hasOne`|一對一HAS ONE| |`belongsTo`|一對一BELONGS TO| |`hasMany`|一對多 HAS MANY| |`hasManyThrough`|遠程一對多 HAS MANY THROUTH| |`belongsToMany`|多對多 BELONGS TO MANY| |`morphMany`|多態一對多 MORPH MANY| |`morphTo`|多態 MORPH TO| >[info] 具體的關聯定義方法可以參考官方手冊,不是文本的重點,因此不做詳細說明。 以一個簡單的博客和分類表為例,每個分類下有多個博客,這就屬于一對多關聯(`hasMany`),每篇博客都屬于某個分類,這就是一對一關聯(`blongsTo`),博客模型的`cate_id`和分類模型的`id`屬性則是兩個模型關聯的紐帶和約束。 具體的關聯定義如下: 博客模型 ``` <?php namespace app\index\model; use think\Model; class Blog extends Model { /** * 獲取博客所屬的分類 */ public function cate() { return $this->belongsTo('Cate'); } } ``` 如果你的模型都在同一個命名空間下,直接使用模型名稱就行,如果不在同一個命名空間下,則需要給出完整的類名,例如: ``` <?php namespace app\index\model; use think\Model; class Blog extends Model { /** * 獲取博客所屬的分類 */ public function cate() { return $this->belongsTo(\app\common\Cate::class); } } ``` 分類模型 ``` <?php namespace app\index\model; use think\Model; class Cate extends Model { /** * 獲取分類下的所有博客信息 */ public function blogs() { return $this->hasMany('Blog'); } } ``` 當我們查詢到某個博客數據的時候,可以很簡單的通過模型關聯獲取到分類數據。 ``` // 查詢博客數據 $blog = Blog::find(3); // 獲取博客所屬分類模型 $cate = $blog->cate; ``` 如果沒有使用模型關聯的設計,你必須使用下面的方法獲取分類數據。 ``` // 查詢博客數據 $blog = Blog::find(3); // 獲取博客所屬分類模型 $cate = Cate::where('id', $blog->cate_id)->find(); ``` 很明顯,模型關聯能夠簡化多個模型之間的查詢,關聯關系越是復雜,帶來的效果更明顯。 需要的時候關聯關系本身還可以多級嵌套,例如: ``` // 查詢博客數據 $blog = Blog::find(3); // 獲取作者的檔案 $info = $blog->user->profile; ``` 通過模型的屬性方式是獲取關聯模型數據的最簡單的一種方式,該方式會查詢滿足關聯條件的所有關聯數據。 對于一對多關聯而言,如果只需要獲取部分關聯數據,就需要改成關聯方法的調用方式,下面一個例子給出了兩種方式代碼的區別。 ``` $cate = Cate::find(1); // 獲取當前分類下所有的博客 $blogs = $cate->blogs; // 獲取當前分類的最新三條博客 $blogs = $cate->blogs() ->order('create_time', 'desc') ->limit(3) ->select(); ``` 至于具體的關聯方法怎么定義,可以參考官方手冊,已經給出了明確的說明,就不再多說了,這里總結一些注意事項。 ## 駝峰命名的關聯方法獲取 關于關聯定義有一個很多開發者容易混淆的地方,所有的關聯方法定義必須使用首字母小寫的駝峰命名規范,但在獲取關聯屬性的時候,則推薦使用小寫+下劃線方式的對應屬性名稱,但方法調用依然是保持駝峰命名。 舉例說明如下: ``` <?php namespace app\index\model; use think\Model; class Cate extends Model { /** * 獲取分類下的所有博客信息 */ public function currentBlogs() { return $this->hasMany('Blog'); } } ``` 關聯查詢代碼 ``` $cate = Cate::find(1); // 獲取當前分類下所有的博客 $blogs = $cate->current_blogs; // 獲取當前分類的最新三條博客 $blogs = $cate->currentBlogs() ->order('create_time', 'desc') ->limit(3) ->select(); ``` ## 一個關聯關系可以定義多個關聯方法 一個關聯關系并不代表只能定義一個關聯方法,我們可以為不同的查詢需求定義多個不同的關聯方法,以分類和博客的一對多關聯關系為例,我們可以這樣定義。 ``` <?php namespace app\index\model; use think\Model; class Cate extends Model { /** * 獲取分類下的所有博客信息 */ public function blogs() { return $this->hasMany('Blog'); } /** * 獲取分類下的最新三條博客信息 */ public function lastThreeBlog() { return $this->hasMany('Blog') ->order('create_time', 'desc') ->limit(3); } } ``` >[info] 你可以在模型關聯方法中使用查詢構造器完成對關聯數據的條件約束,`5.1`版本的話還可以支持在關聯方法中調用模型的自定義方法。 可以通過下面的代碼來調用不同的關聯數據。 ``` $cate = Cate::find(1); // 獲取當前分類下所有的博客 $blogs = $cate->blogs; // 獲取當前分類的最新三條博客 $blogs = $cate->last_three_blog ``` ## 關聯方法定義支持參數 還是上面的需求,我們希望獲取最近的N條博客數據,但希望具體多少條在查詢的時候傳入,這需要我們首先給關聯方法增加一個參數。 ``` /** * 獲取分類下的最新N條博客信息 */ public function lastBlog($number = 3) { return $this->hasMany('Blog') ->order('create_time', 'desc') ->limit($number); } ``` 查詢的時候使用 ``` $cate = Cate::find(1); // 獲取當前分類下最新的10條博客 $blogs = $cate->lastBlog(10)->select(); ``` ## 典型的`N+1`查詢問題 如果要查詢3個分類,以及每個分類的博客數據,按照普通的關聯查詢就會產生3+1次查詢,隨著數據量的越來越大查詢次數會越來越多,性能也會急劇下降。 ``` $cates = Cate::select([1,2,3]); foreach($cates as $cate) { $blogs = $cate->blogs; } ``` 如果查看頁面Trace信息可以看到當前產生了4次查詢操作。 預載入查詢就是為了解決這個`N+1`問題而應運而生的,我們只要把代碼改成如下: ``` $cates = Cate::with(['blogs'])->select([1,2,3]); foreach($cates as $cate) { $blogs = $cate->blogs; } ``` 你會發現最終產生的查詢次數為2次,事實上無論有多少分類數據,最終的查詢次數都是2次,很好的解決了查詢性能問題。 >[info] `with`方法支持同時指定多個關聯方法,因此使用數組參數是更好的規范。 ## 預載入查詢的數據篩選 預載入查詢的數據篩選有兩種方式,第一種方式前面我們已經介紹過了,就是為該關聯關系增加額外的方法定義,然后在方法里面進行查詢條件的篩選,這種對于有明確的篩選需求比較有效,查詢代碼也比較簡單。 ``` $cates = Cate::with(['last_three_blog']) ->select([1,2,3]); ``` >[info] `with`方法中的關聯方法名可以是實際的關聯定義方法名,也可以是關聯方法名的小寫+下劃線轉換名。 第二種方式就是在預載入查詢的時候通過閉包動態指定查詢條件。 ``` // 給預載入查詢指定篩選條件 $cates = Cate::with(['blogs' => function($query){ $query->order('create_time', 'desc')->limit(3); }])->select([1,2,3]); ``` ## 延遲預載入 關聯預載入查詢并非是惰性的,無論最后數據是否需要使用,查詢已經產生了,有些情況下,需要根據查詢出來的數據來決定是否需要使用關聯預載入,使用延遲預載入可以實現關聯數據的惰性查詢,有效提高性能,避免浪費不必要的查詢。 ``` $cates = Cate::select([1,2,3]); // 使用延遲預載入查詢關聯數據 $cates->load('blogs'); foreach($cates as $cate) { $blogs = $cate->blogs; } ``` ## 關聯統計 經常會有一些對關聯數據進行聚合統計的需求,框架提供了便捷的關聯統計方法。 ``` $cates = Cate::withCount(['blogs']) ->select([1,2,3]); foreach($cates as $cate) { // 獲取分類下的博客總數 echo $cate->blogs_count; } ``` 如果要改變默認的統計字段名稱,可以改成 ``` $cates = Cate::withCount(['blogs' => 'blog_count']) ->select([1,2,3]); foreach($cates as $cate) { // 獲取分類下的博客總數 echo $cate->blog_count; } ``` 也支持使用閉包方式進行統計查詢的條件限制 ``` $cates = Cate::withCount(['blogs' => function($query) { $query->where('status', 1); }])->select([1,2,3]); foreach($cates as $cate) { // 獲取分類下的博客總數 echo $cate->blogs_count; } ``` 除了`count`統計外,還支持`sum/max/min/avg`等聚合統計。 ``` $cates = Cate::withSum(['blogs' => 'total_read'],'read_count') ->select([1,2,3]); foreach($cates as $cate) { // 獲取分類下的博客閱讀總數 echo $cate->total_read; } ``` >[info] 關聯統計查詢用的是子查詢方式,所以并不會增加額外的查詢次數。 ## 關聯數據輸出 使用了關聯查詢后,依然可以使用`hidden`/`visible`/`append`方法進行模型數據的輸出調整。 ``` $blog = Blog::with('cate')->find(1); // 隱藏分類的部分屬性 $blog->hidden(['cate' => ['remark', 'create_time', 'update_time']]) ->toArray(); ``` ## 根據關聯條件查詢 ``` // 查詢博客超過10個的分類 $cates = Cate::has('blogs','>',10)->select(); // 查詢最近3天發過博客的分類 $cates = Cate::hasWhere('blogs', function($query) { $query->whereTime('create_time', '-3 days'); })->select(); ``` 閉包里面的查詢條件是關聯模型的約束,如果你需要添加主模型的額外約束條件,可以單獨追加使用`where`方法或者其它的查詢構造器,不過要注意由于`hasWhere`方法使用的是`JOIN`查詢,在查詢條件中要指定別名。 ``` // 查詢最近3天發過博客并且狀態正常的分類 按name排序 $cates = Cate::hasWhere('blogs', function($query) { $query->whereTime('create_time', '-3 days'); })->where('Cate.status', 1) ->order('Cate.name') ->select(); ``` ## 自關聯 如果你的模型關聯到自身(例如子分類和分類的關聯關系),就需要在定義關聯的時候設置自關聯。 ``` <?php namespace app\index\model; use think\Model; class Cate extends Model { /** * 獲取分類下的所有博客信息 */ public function blogs() { return $this->hasMany('Blog'); } /** * 獲取當前分類的子分類 */ public function sub() { return $this->hasMany('Cate', 'parent_id') ->selfRelation(); } } ``` 關聯查詢代碼 ``` $cate = Cate::with('sub')->find(1); ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看