我們已經了解如何使用 Active Record (AR) 從單一資料表中取得資料。 在本節中,我們講解如何使用 AR 連接多個相關 資料表並取回關聯(join)後的資料集。
為了使用關係型 AR,我們建議在需要關聯的表中定義主鍵-外鍵約束。這些約 束可以幫助保證相關資料的一致性和完整性。
本例透過修改Yii Framework 開發教學(25) 資料庫-Query Builder範例來 介紹多個有關聯的表格如何使用Active Record。
在我們使用 AR 執行關聯查詢之前,我們需要讓 AR 知道一個 AR 類別是怎麼 樣關聯到另一個的。
兩個 AR 類別之間的關係直接透過 AR 類別所代表的資料表之間的關係相關聯。 從資料庫的角度來說, 表A 和B 之間有三種關係:一對多(one-to-many,例如tbl_user 和tbl_post),一對一( one-to-one 例如tbl_user 和tbl_profile)和多對多(many-to-many 例如tbl_category 和tbl_post)。 在AR 中,有四種關係:
BELONGS_TO( 屬於): 如果表A 和B 之間的關係是一對多,則表B 屬於表A (例如Post 屬於User);
HAS_MANY(有多個): 如果表A 和B 之間的關係是一對多,則A 有多個B (例如User 有多個Post);
HAS_ONE(有一個): 這是HAS_MANY 的一個特例,A 最多有一個B (例如User 最多有一個Profile);
MANY_MANY: 這個對應於資料庫中的多對多關係。 由於多數 DBMS 不直接支援 多對多 關係,因此需要有一個關聯表將 多對多 關係分割為 一對多 關係。 在我們的範例資料結構中, tbl_post_category 就是用於此目的的。在 AR 術語中,我們可以解釋 MANY_MANY 為 BELONGS_TO 和 HAS_MANY 的組合。 例如 ,Post 屬於多個(belongs to many) Category ,Category 有多個(has many) Post.
AR 中定義關係需要覆蓋 CActiveRecord 中的 relations() 方法。此方法傳回一個關係配置陣列。每個數組元素透過如下格式表示單一的關係。
在Query Builder中我們使用了下面SQL查詢語句
SELECT c.FirstName, c.LastName , c.Address,c.Email FROM customer c INNER JOIN employee e ON c.SupportRepId=e.EmployeeId
WHERE e.EmployeeId=4涉及兩個表格Employee 和Customer,Employee和Customer之間是一對多的關係,也就是說一個員工可以負責多個客戶。 Employee到Customer的關係式為HAS_MANY, Customer到Employee的關係式為HAS_ONE。因此可以定義 Employee和Customer如下:
//Customer.phpclass Customer extends CActiveRecord{ public static function model($className=__CLASS__){return parent::model($className);} public function tableName(){return 'Customer';} } //Employee.phpclass Employee extends CActiveRecord{ public static function model($className=__CLASS__){return parent::model($className);} public function tableName(){return 'Employee';} public function relations(){return array('customers'=>array(self::HAS_MANY, 'Customer', 'SupportRepId'), );}}
因為本例只使用到由Employee查詢對應的Customer,因此只為類別定義了relations方法。對應的表和外鍵為Customer 和SupportRepId。
接著修改SiteController的indexAction方法:
public function actionIndex(){ $employee=Employee::model()->findByPk(4); $this->render('index', array('model' => $employee->customers, ));}
AR 類別中的關係定義為每個關係式為類別中隱式新增了一個屬性。在一個關聯查詢執行後,對應的屬性將會被以關聯的 AR 實例填入。因此由$employee->customers可以查詢到Employee對應的Customers記錄。
執行關聯查詢最簡單的方法是讀取 取一個 AR 實例中的關聯屬性。如果此屬性以前沒有被訪問過,則一個關聯查詢將被初始化,它將兩個表關聯並使用當前 AR 實 例的主鍵過濾。 查詢結果將以所關聯 AR 類別的實例的方式儲存到屬性中。這就是傳說中的 懶惰式加載(lazy loading,也可譯 為延遲加載) 方式,例如,關聯查詢只在關聯的對象首次被訪問時執行。
本例使用的為延遲加載,延遲加載在某些情況 下並不高效。如果我們想要取得 N 個貼文的作者,使用這種延遲載入將會導致執行 N 個關聯查詢。 在這種情況下,我們應該改為 使用 渴求式加載(eager loading)方式。
渴求式載入方式會在取得主 AR 實例的同時取得關聯的 AR 實例。 這是透過 在使用 AR 中的 find 或 findAll 方法時配合使用 with 方法完成的。例如:
$employee=Post::model()->with ('customers')->findAll();
最後修改一下顯示結果的View的程式碼:
$customer){ echo 'First Name:' . $customer->FirstName . ''; echo 'Last Name:' . $customer->LastName . ''; echo 'Address:' . $customer->Address . ''; echo 'Email:' . $customer->Email . ''; echo '----------------------';} ?>
不同的資料對列名大小寫處理方式不同,有的資料庫區分大小寫,保險起見,Customer的屬性使用和列定義相同的大小寫。
本例介紹了關聯Active Record的最基本的用法,其它功能和屬性可以參見Yii中文文檔,此外如果借助類似CodeSmith這樣的工具,如果能夠自動生成數據庫定義的ActiveRecord代碼,就可以大大減輕程式設計師的程式碼手動編寫工作量。
此外,使用Active Record的便利性是以效能為代價的,通常情況下使用Active Record與使用DAO讀寫資料庫效能相比要差一 個層級。下表為一個參考值,找出200個演員和1000部電影。
以上就是PHP開發框架Yii Framework教程(27) 資料庫-關聯Active Record範例的內容,更多相關內容請關注PHP中文網(www.php.cn)!