[TOC]
# 獲取一對多關聯表的數據
AR模型提供了一種面向對象的操作方法讓我們獲取關聯表,這回我拿用戶和發表文章來說說
如果在Yii里查用戶發表的文章,這樣的代碼是很菜的行為,我并不建議這樣寫:
~~~php
$user = User::findOne($userId);
$articles = Article::findAll(['user_id' => $user->id]);
foreach($articles as $article){
echo $article->title . '<br/>';
}
~~~
# 通過getter定義關系
基于本文章的例子,官方推薦我們在`User`模型里建立一個getter方法來獲取所有文章(在[Object 基類的特性](http://www.kkh86.com/it/yii2/guide-base-object.html)里有介紹過getter嘛,怕你忘了我提醒一下)
這個getter是這樣寫的:
~~~php
public function getArticles(){
$關聯表的類名 = Article::className();
$關聯表的字段 = 'user_id';
$本表的字段 = 'id';
return $this->hasMany($關聯表的類名, [$關聯表的字段 => $本表的字段]);
}
~~~
這樣的話就可以這樣獲取用戶的所有文章了:
~~~php
$user = User::findOne($userId); //查詢一個用戶的記錄
foreach($user->articles as $article){ //掃描這個用戶的文章
echo $article->title . '<br/>';
}
~~~
這樣的代碼看上去是不是**更加有可讀性**?至少讓調用代碼變得更短了
你可能會覺得這樣有點裝飾花哨,但根據一個用戶的ID去查他的各種關聯數據的場景是經常有的,如果定義了getter就能在調用時簡寫一點了,而且代碼也非常有可讀性,語義簡練
我解析一下這個`hasMany`方法,它是用在`一對多的兩張關聯表`場景里的,用戶表有id字段,article表有user\_id字段來關聯用戶,每條user表的記錄里的用戶都可以在article表里有多條文章記錄
最終hasMany方法返回的是一個AR查詢器,當使用這個查詢器時底層和Article::findAll一樣也實現了獲取所有文章
hasMany的第一個參數就是要關聯的表名;第2個參數就是關聯關系(關聯數組),這個關系中,`本表的字段要放在$value部分`才可以
# 跨數據庫關系聲明
這個會很少用吧,但比較容易明白所以順便講講
我們目前講到的AR模型默認就是指[yii\\db\\ActiveRecord](http://www.yiichina.com/doc/api/2.0/yii-db-activerecord),這是基于主流SQL關系數據庫層面上定義的AR模型,其實還有一種AR模型就是[yii\\mongodb\\ActiveRecord](http://www.yiiframework.com/doc-2.0/yii-mongodb-activerecord.html)(需要安裝[yii-mongodb擴展](http://www.yiiframework.com/doc-2.0/ext-mongodb-index.html)),下面代碼中的兩個模型可以實現互相定義關系獲取對方的數據(基于官方示例代碼稍作了修改):
~~~php
//Customer表對應的AR模型,假設在MySql里
class Customer extends \yii\db\ActiveRecord
{
public static function tableName(){
return 'customer';
}
public function getComments(){
//聲明與comment的一對多關系
return $this->hasMany(Comment::className(), ['customer_id' => 'id']);
}
}
// Comment是在mongoDb里的comment集合
class Comment extends \yii\mongodb\ActiveRecord //注意繼承
{
public static function collectionName(){
return 'comment';
}
public function getCustomer(){
//聲明與customer的一對一關系
return $this->hasOne(Customer::className(), ['id' => 'customer_id']);
}
}
$customer = Customer::findOne(1);
echo count($customer->comments); //輸出評論數,底層會構造與mongoDb之間的查詢處理
$comment = Comment::findOne(99);
echo $comment->customer->name; //輸出客戶名稱
~~~
關于Yii里用mongoDb的AR模型,有需要的請去翻一下官方資料,我暫時未計劃寫這部分,至少我對mongoDb也不是很熟悉
# 查詢指定字段時的with注意事項
~~~php
$orders = Order::find()->select(['id', 'amount'])->with('customer')->all();
echo $orders[0]->customer; // 空的
~~~
不是with一起查出來了嗎?為什么是空的呢?
因為with的附加查詢里需要關聯字段才可以,但是select指定的id和amount兩個字段都不是與customer表發生關聯的字段,所以在底層進行with附加的查詢時,根本找不到關聯字段,所以沒查到相關數據
所以這里要注意的是,select要附加上關聯字段,以下才是正確姿勢:
~~~php
$orders = Order::find()->select(['id', 'amount', 'customer_id'])->with('customer')->all();
~~~
那如果突然想要在in的同時又加上其它條件,就要在with里換一下參數的寫法了:
~~~php
// SELECT * FROM customer LIMIT 100;
// SELECT * FROM orders WHERE customer_id IN (1,2,...) AND status = 1
$customers = Customer::find()->limit(100)->with([
'orders' => function($arQuery){
//傳來的參數是一個AR查詢器,通過查詢器提供的API來調整with查詢的條件,比如andWhere
$query->andWhere(['status' => 1]);
}
])->all();
~~~
- 目錄
- 配置
- 簡介
- 別名
- gii
- 配置項
- 模型
- 簡介
- 增刪改查
- AR和model
- 模型事件
- 場景
- query查詢
- 增刪改
- AR查詢器
- 模型關系定義
- AR模型連表查詢
- fields
- where拼接
- 模塊
- 創建模塊
- 控制器
- 表單
- 跳轉
- 響應
- 驗證器
- Action
- 組件
- url
- 分頁
- 驗證碼
- 緩存
- 文件上傳
- 預啟動組件
- 事件
- 自定義組件
- redis
- 日志
- 行為
- cookie和session
- 基礎知識
- 創建一個類
- 配置一個類
- object基類
- component組件類特性
- phpstorm無法更改php等級
- url地址美化
- 過濾器
- 請求處理
- 請求組件
- 響應組件
- header
- 用戶登錄
- 實現IdentityInterface接口
- 登錄
- 自動檢測登錄
- 獲取用戶信息
- 訪問行為追蹤
- phpstorm+postman斷點調試