- 前提條件
在組織數據庫時,需要使用主鍵與外鍵約束才能使用ActiveReocrd的關係操作;
- 場景
下面的一個ER圖顯示的是一個例子
ER圖
申明關係
兩張表之間的關係無非三種:一對多;一對一;多對多; 在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 | 這個對應多對多的情況,在AR裏會將多對多以BELONGS_TO和HAS_MANY的組合來解釋 | Post和Category |
在AR中通過重寫CActiveRecord類的relations()方法來申明關係;這個方法返回一個關係配置的數組;一個數組無素代表一個單獨的關係,格式如下:
'VarName'=>array('RelationType','ClassName','ForeignKey',...additional options)
VarName | 關係名 |
---|---|
RelationType | 四種關係:self::BELONGS_TO, self::HAS_ONE, self::HAS_MANY,self::MANY_MANY |
ClassName | 代表當前AR類要關聯的那個AR類名 |
ForeignKey | 實現關係的外鍵, 有可能有多個,即列名 |
下面的代碼表示用來定義Post, User之間的關係
class Post extends CActiveRecord
{
......
public function relations()
{
return array(
'author'=>array(self::BELONGS_TO, 'User', 'author_id'),
'categories'=>array(self::MANY_MANY, 'Category',
'tbl_post_category(post_id, category_id)'),
);
}
}
class User extends CActiveRecord
{
......
public function relations()
{
return array(
'posts'=>array(self::HAS_MANY, 'Post', 'author_id'),
'profile'=>array(self::HAS_ONE, 'Profile', 'owner_id'),
);
}
}
使用時,如果$author代表一個USER的AR實例,可以使用$author->posts來獲取到它相關的所有的Post對象。
執行關係查詢
懶惰導入查詢方法
最簡單的方法就是爲AR對象添加一個關聯屬性,
例:
// 獲取PK爲10的POST對象
$post=Post::model()->findByPk(10);
// 獲取這個POST的作者
$author=$post->author;
如果沒有關聯的對象,那麼將返回NULL或者一個空數組;BELONGS_TO和HAS_ONE結果爲NULL,而HAS_MANY和MANY_MANY返回一個空數組。
上面的這種“懶惰導入”方法使用起來非常方便,但是在一些場景下不是非常的效率,比如,如果我們想訪問N個POST的作者的信息,使用這種懶惰導入的方法將會執行N個join查詢;
急切導入查詢方法
下面介紹是一種“急切導入”方法:在使用find和findAll時,使用with()方法,例:
$posts=Post::model()->with('author')->findAll()
這樣就可以在一次查詢時連同查詢其他信息了;with方法可以接受多個關係:
$posts=Post::model()->with('author','categories')->findAll();
這樣就可以將作者和類別的信息一併進行查詢;同樣,with還支持多重急切導入
$posts=Post::model()->with(
'author.profile',
'author.posts',
'categories')->findAll();
上面的代碼不僅會返回autho和categories信息,還會返回作者的profile和posts信息
這種“急切導入”方法也支持CDbCriteria::with,下面這兩種實現方式效果一樣:
$criteria=new CDbCriteria;
$criteria->with=array(
'author.profile',
'author.posts',
'categories',
);
$posts=Post::model()->findAll($criteria);
or
$posts=Post::model()->findAll(array(
'with'=>array(
'author.profile',
'author.posts',
'categories',
)
);
關係查詢選項
前面提過,在申明關係時可以添加額外的選項,這些選項都是一些key-value對,是用來定製關係查詢的,總結如下:
- select
- 定義從AR類中被select的列集合,如果定義爲*,則表示查詢所有列
- condition
- 定義where語句,默認爲空。
- params
- 生成SQL語句的參數,這個需要用一個key-value對的數組來表示;
- on
- ON語句,這個條件用來通過AND添加一個joining condintion語句
- order
- ORDER語句
- with
- 和當前對象一起導出的相關對象列表,要注意如果使用不正確,有可能導致無限死循環;
- joinType
- 定義join的類別,默認爲LEFT OUTER JOIN
- alias
- 定義別名,當多個表中有相同的columnname時,需要爲表格定義alias,然後使用tablename.columnname來指定不同的column
- together
- 這個只在HAS_MANY,MANY_MANY時有用,在實現跨表查詢時,可以用這個參數來控制性能。正常用不到,不詳細講述;
- join
- JOIN語句
- group
- GROUP語句
- having
- HAVING語句
- index
- 這個值用來設定返回的結果數組以哪個column做爲index值,如果不設定這個值的話,將從0開始組織結果數組。
除此之外還包含下面幾個選項,在“懶惰導出”的特定關係時可用
- limit
- 返回結果數量的限制,不適用於BELONG_TO關係
- offset
- offset結果數量的值,不適用於BELONG_TO關係
下面代碼,顯示上面選項的一些使用:
class User extends CActiveRecord
{
public function relations()
{
return array(
'posts'=>array(self::HAS_MANY, 'Post', 'author_id',
'order'=>'posts.create_time DESC',
'with'=>'categories'),
'profile'=>array(self::HAS_ONE, 'Profile', 'owner_id'),
);
}
}
此時,我們使用$author->posts時,會返回固定ORDER的POST信息