## 模型關聯
通過模型關聯操作把數據表的關聯關系對象化,解決了大部分常用的關聯場景,封裝的關聯操作比起常規的數據庫聯表操作更加智能和高效,并且直觀。
>[danger] 避免在模型內部使用復雜的`join`查詢和視圖查詢。
從面向對象的角度來看關聯的話,模型的關聯其實應該是模型的某個屬性,比如用戶的檔案關聯,就應該是下面的情況:
~~~
// 獲取用戶模型實例
$user = User::find(1);
// 獲取用戶的檔案
$user->profile;
// 獲取用戶的檔案中的手機資料
$user->profile->mobile;
~~~
為了更方便和靈活的定義模型的關聯關系,框架選擇了方法定義而不是屬性定義的方式,每個**關聯屬性**其實是對應了一個模型的(關聯)方法,這個關聯屬性和模型的數據一樣是動態的,并非模型類的實體屬性。
例如上面的關聯屬性就是在`User`模型類中定義了一個`profile`方法(`mobile`屬性是`Profile`模型的屬性):
~~~
<?php
namespace app\model;
use think\Model;
class User extends Model
{
public function profile()
{
return $this->hasOne(Profile::class);
}
}
~~~
>[danger] 一個模型可以定義多個不同的關聯,增加不同的關聯方法即可
同時,我們必須定義一個`Profile`模型(即使是一個空模型)。
~~~
<?php
namespace app\model;
use think\Model;
class Profile extends Model
{
}
~~~
關聯方法返回的是不同的關聯對象,例如這里的`profile`方法返回的是一個`HasOne`關聯對象(`think\model\relation\HasOne`)實例。
當我們訪問`User`模型對象實例的`profile`屬性的時候,其實就是調用了`profile`方法來完成關聯查詢。
按照`PSR-2`規范,模型的方法名都是駝峰命名的,所以系統做了一個兼容處理,如果我們定義了一個`userProfile`的關聯方法的時候,在獲取關聯屬性的時候,下面兩種方式都是有效的:
~~~
$user->userProfile;
$user->user_profile; // 建議使用
~~~
>[danger] 推薦關聯屬性統一使用后者,和數據表的字段命名規范一致,因此在很多時候系統自動獲取關聯屬性的時候采用的也是后者。
可以簡單的理解為關聯定義就是在模型類中添加一個方法(注意不要和模型的對象屬性以及其它業務邏輯方法沖突),一般情況下無需任何參數,并在方法中指定一種關聯關系,比如上面的`hasOne`關聯關系,`6.0`版本支持的關聯關系包括下面8種,后面會給大家陸續介紹:
|模型方法|關聯類型|
|---|---|
|`hasOne`|一對一|
|`belongsTo`|一對一|
|`hasMany`|一對多 |
|`hasOneThrough`|遠程一對一 |
|`hasManyThrough`|遠程一對多 |
|`belongsToMany`|多對多 |
|`morphMany`|多態一對多 |
|`morphOne`|多態一對一 |
|`morphTo`|多態 |
關聯方法的第一個參數就是要關聯的模型名稱,也就是說當前模型的關聯模型必須也是已經定義好的一個模型。
也可以使用完整命名空間定義,例如:
~~~
<?php
namespace app\model;
use think\Model;
class User extends Model
{
public function profile()
{
return $this->hasOne(Profile::class);
}
}
~~~
兩個模型之間因為參照模型的不同就會產生相對的但不一定相同的關聯關系,并且相對的關聯關系只有在需要調用的時候才需要定義,下面是每個關聯類型的相對關聯關系對照:
|類型|關聯關系|相對的關聯關系|
|---|---|---|
|一對一|`hasOne`|`belongsTo`|
|一對多|`hasMany`|`belongsTo`|
|多對多|`belongsToMany`|`belongsToMany`|
|遠程一對多|`hasManyThrough`|不支持|
|多態一對一|`morphOne`|`morphTo`|
|多態一對多|`morphMany`|`morphTo`|
例如,`Profile`模型中就可以定義一個相對的關聯關系。
~~~
<?php
namespace app\model;
use think\Model;
class Profile extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
~~~
在進行關聯查詢的時候,也是類似,只是當前模型不同。
~~~
// 獲取檔案實例
$profile = Profile::find(1);
// 獲取檔案所屬的用戶名稱
echo $profile->user->name;
~~~
如果是數據集查詢的話,關聯獲取的用法如下:
~~~
// 獲取檔案實例
$profiles = Profile::where('id', '>', 1)->select();
foreach($profiles as $profile) {
// 獲取檔案所屬的用戶名稱
echo $profile->user->name;
}
~~~
如果你需要對關聯模型進行更多的查詢約束,可以在關聯方法的定義方法后面追加額外的查詢鏈式方法(但切忌不要濫用,并且不要使用實際的查詢方法),例如:
~~~
<?php
namespace app\model;
use think\Model;
class User extends Model
{
public function book()
{
return $this->hasMany(Book::class)->order('pub_time');
}
}
~~~
>[danger] 模型關聯支持調用模型的方法
>[info] 具體不同的關聯關系的詳細使用,請繼續參考后面的內容。
- 序言
- 基礎
- 安裝
- 開發規范
- 目錄結構
- 配置
- 架構
- 請求流程
- 架構總覽
- 入口文件
- 多應用模式
- URL訪問
- 容器和依賴注入
- 服務
- 門面
- 中間件
- 事件
- 路由
- 路由定義
- 變量規則
- 路由地址
- 路由參數
- 路由中間件
- 路由分組
- 資源路由
- 注解路由
- 路由綁定
- 域名路由
- MISS路由
- 跨域請求
- URL生成
- 控制器
- 控制器定義
- 基礎控制器
- 空控制器
- 資源控制器
- 控制器中間件
- 請求
- 請求對象
- 請求信息
- 輸入變量
- 請求類型
- HTTP頭信息
- 偽靜態
- 參數綁定
- 請求緩存
- 響應
- 響應輸出
- 響應參數
- 重定向
- 文件下載
- 數據庫
- 連接數據庫
- 分布式數據庫
- 查詢構造器
- 查詢數據
- 添加數據
- 更新數據
- 刪除數據
- 查詢表達式
- 鏈式操作
- where
- table
- alias
- field
- strict
- limit
- page
- order
- group
- having
- join
- union
- distinct
- lock
- cache
- cacheAlways
- comment
- fetchSql
- force
- partition
- failException
- sequence
- replace
- extra
- duplicate
- procedure
- 聚合查詢
- 分頁查詢
- 時間查詢
- 高級查詢
- 視圖查詢
- JSON字段
- 子查詢
- 原生查詢
- 獲取查詢參數
- 查詢事件
- 獲取器
- 事務操作
- 存儲過程
- 數據集
- 數據庫驅動
- 模型
- 定義
- 模型字段
- 新增
- 更新
- 刪除
- 查詢
- 查詢范圍
- JSON字段
- 獲取器
- 修改器
- 搜索器
- 數據集
- 自動時間戳
- 只讀字段
- 軟刪除
- 類型轉換
- 模型輸出
- 模型事件
- 模型關聯
- 一對一關聯
- 一對多關聯
- 遠程一對多
- 遠程一對一
- 多對多關聯
- 多態關聯
- 關聯預載入
- 關聯統計
- 關聯輸出
- 虛擬模型
- 視圖
- 模板變量
- 視圖過濾
- 模板渲染
- 模板引擎
- 視圖驅動
- 錯誤和日志
- 異常處理
- 日志處理
- 調試
- 調試模式
- Trace調試
- SQL調試
- 變量調試
- 遠程調試
- 驗證
- 驗證器
- 驗證規則
- 錯誤信息
- 驗證場景
- 路由驗證
- 內置規則
- 表單令牌
- 注解驗證
- 雜項
- 緩存
- Session
- Cookie
- 多語言
- 上傳
- 命令行
- 啟動內置服務器
- 查看版本
- 自動生成應用目錄
- 創建類庫文件
- 清除緩存文件
- 生成數據表字段緩存
- 生成路由映射緩存
- 輸出路由定義
- 自定義指令
- Debug輸出級別
- 擴展庫
- 數據庫遷移工具
- Workerman
- think助手工具庫
- 驗證碼
- Swoole
- 附錄
- 助手函數
- 升級指導
- 更新日志