現在有客戶表、訂單表、圖書表、作者表,
- 客戶表Customer (id customer_name)
- 訂單表Order (id order_name customer_id book_id)
- 圖書表 (id book_name author_id)
-
作者表 (id author_name)
模型定義
下面是這4個個模型的定義,只寫出其中的關聯
Customer
Order
Book
Author
hasMany、hasOne使用
Yii2中的表之間的關聯有2種,它們用來指定兩個模型之間的關聯。
- 一對多:hasMany
-
一對一:hasOne
- 返回結果:這兩個方法的返回結果都爲yii\db\ActiveQuery對象
- 第一個參數:所關聯的模型的類名稱。
-
第二個參數:是一個數組,其中鍵爲所關聯的模型中的屬性,值爲當前模型中的屬性。
關聯的使用
現在我們獲取一個客戶的所有的訂單信息
上面的兩行代碼會生成如下sql語句
關聯結果緩存
如果客戶的訂單改變了,我們再重新調用
再次得到訂單的時候你會發現沒有變化。原因是只會在第一次執行$customer->orders的時候纔會去數據庫裏面查詢,然後會把結果緩存起來,以後查詢的時候都不會再執行sql。
那麼如果我想再次執行sql如何做呢?可以執行
然後就可以從數據庫裏面取數據了。
定義多個關聯
同樣,我們還可以在Customer裏面定義多個關聯。
如返回總數大於100的訂單。
關聯的兩種訪問方式
如上面的,如果使用 將會得到大於100的所有的訂單。如果要返回大於200的訂單可以這樣寫 從上面可以看出訪問一個關聯的時候有兩種方法
- 如果以函數的方式調用,會返回一個 ActiveQuery 對象($customer->getOrders()->all())
-
如果以屬性的方式調用,會直接返回模型的結果($customer->orders)
with的使用
看如下代碼,是取一個客戶的訂單
如果現在我們要取出100個用戶,然後訪問每個用戶的訂單,從上面的瞭解我們可能會寫出如下代碼
然而,如果真要這樣寫的話,會在foreach的每個循環裏面都執行一次sql去數據庫裏面查詢數據。因爲每個$customer對象都是不一樣的。
爲了解決上面的問題 可以使用 yii\db\ActiveQuery::with()。
其中width的參數爲關係的名稱,也就在model裏面定義的getOrders,getCustomer中的orders和customer
如果使用了select來指定返回的列,一定要確保返回的列裏面包含所關聯的模型的關聯字段,否則將不會返回關聯的表的Model
給with加過濾條件
查詢一個客戶大於100的訂單
查詢100個客戶的,每個客戶的總合大於100的訂單
在這裏width的參數爲數組,鍵爲關聯的名稱,值爲回調函數。
也就是說 對orders這個關聯返回的ActiveQuery,再執行一次$query->andWhere('subtotal>100');
使用joinWith進行表關聯
我們都知道可以用join on來寫多個表之間的關聯。先看看yii2中joinWit的聲明
joinWith( $with, $eagerLoading = true, $joinType = 'LEFT JOIN' )
-
$with 數據類型爲字符串或數組,
如果爲字符串,則爲模型中定義的關聯的名稱(可以爲子關聯)。
如果爲數組,鍵爲model中以getXXX格式定義的關聯,值爲對這個關聯的進一步的回調操作。 - $eagerLoading 是否加載在$with中關聯的模型的數據。
-
$joinType 聯接類型,可用值爲:LEFT JOIN、INNER JOIN,默認值爲LEFT JOIN
在實現上,Yii 先執行滿足JOIN查詢條件的SQL語句,把結果填充到主模型中, 然後再爲每個關聯執行一條查詢語句, 並填充相應的關聯模型。
On條件
在定義關聯的時候還可以指定on條件
在joinWith中使用
如果沒有使用join操作,即使用的是with 或者 直接以屬性來訪問關聯。這個時候on條件會作爲where 條件。