我们已经了解了怎样通过AR从单个数据表中获取数据,那么如果要关联多个数据表,AR又应该怎样操作列
我们看到,在 创建的AR模型User类里面有一个relations方法,它就是用来返回与当前表关联关系的
一、声明关系
要想在AR中使用关联查询,我们需要先申明user表与其他表的关联关系
AR中有四中关联关系,
BELONGS_TO(属于):比如,一个用户(user)只有一个城市id(city_id),但是一个城市id下面有多个用户,那么用户表就属于城市表,简单的表述就是 A表的多行数据对应B表的一行数据
HAS_MANY(有多个):比如,一个城市对应多个用户,那么城市表就有多个用户表
HAS_ONE(有一个):比如,一个用户只有一个用户简介,那么用户表就有一个用户简介表
MANY_MANY(多对多):比如,一个商家有多个分店,一个商品支持多个分店使用,那么需要一个中间表把商家的分店和商品关联起来,比如商品表Groupon,分店表shop,那么groupon_shop表用来存放商品和分店的关联关系
他们分别代表这几个类
const BELONGS_TO='CBelongsToRelation'; const HAS_ONE='CHasOneRelation'; const HAS_MANY='CHasManyRelation'; const MANY_MANY='CManyManyRelation'; const STAT='CStatRelation';
那么具体怎么去申明列
我们拿user表和city表来做个实例,根据刚才的判断,我们使用Belongs to来定义
先用gii生成一个City模型
public function relations() { // NOTE: you may need to adjust the relation name and the related // class name for the relations automatically generated below. return array( 'city'=>array(self::BELONGS_TO,'City','city_id'), ); }
索引下表city是这个关联关系的名字,是自定义的,在后面调用$user->city可以获取到city表对应的数据
数组的第一个参数是 关系申明
第二个参数是关联的 AR模型
第三个参数是关联的外键名,
如果还需要设置其他的参数,可以在第四个参数用一个数组来设置,具体的可设置的参数参考 关联关系对应的四个类
二、单条语句使用关联查询
1.AR的关联查询支持 延迟加载和饥渴似加载两种
我们先来看延迟加载
在新建一个方法actionRelation
先找出user对象
public function actionRelation($id){ $id = trim($id); //懒惰加载 $user = User::model()->findByPk($id); //此时的user对象的related属性是一个空数组,user对象的打印结果如下图 dump($user);// $city = $user->city;// dump($city); }再调用user对象里面的city关联属性
public function actionRelation($id){ $id = trim($id); //懒惰加载 $user = User : : model() - > findByPk($id); //此时的user对象的related属性是一个空数组,user对象的打印结果如下图// dump($user); //获取与user对象相关联的city对象,调用city属性的时候,会调用relations方法里面city对应的 关联关系 找到city对象 $city = $user - > city; //打印结果见下图 dump($city);
当调用一次city属性之后,延迟加载了city对象 user对象的related属性添加了city对象值
public function actionRelation($id){ $id = trim($id); //懒惰加载 $user = User::model()->findByPk($id); //此时的user对象的related属性是一个空数组,user对象的打印结果如下图// dump($user); //获取与user对象相关联的city对象,调用city属性的时候,会调用relations方法里面city对应的 关联关系 找到city对象 $city = $user->city;// dump($city); //此时我们再打印user对象,related属性就不是一个空数组了,打印结果如下图 dump($user,false); //我们可以像调用user属性一样去调用city对象的属性,比如我想获取城市名 dump($city->name); }
从数据库的角度来说,延迟加载就相当于先查询user表,然后根据city_id查询city表对应的数据
我们再来看看饥渴式加载
//饥渴式加载我们使用到关键词with在find之前 public function actionEager($id){ $id = trim($id); //饥渴式加载 $user = User::model()->with('city')->findByPk($id); dump($user); }
我们看到打印结果,如果使用with关键词之后,默认就已经将city表对应数据加载到user对象的related属性中
//饥渴式加载我们使用到关键词with在find之前 public function actionEager($id){ $id = trim($id); //饥渴式加载 $user = User::model()->with('city')->findByPk($id);// dump($user); //获取城市名称 $name = $user->city->name; //打印结果如下 dump($name); }'广州'
我们看到 当调用$user->city的时候 获取的就是对应的city对象
从数据库的角度来说 饥渴式加载 就相当于join查询user和city两张表 默认的join类型是left join左联查询
我们知道一张表可能会与多个表发生关联关系,比如 又来一张 user_info 表(用户信息表),user_info表里面有一个外键user_id关联表的id,而且user与user_info是一一对应的关系,那么在使用AR关联时,只需要在relations方法里面添加一个user_info
user_info表 建表语句CREATE TABLE `user_info` ( `id` int(10) unsigned NOT NULL auto_increment, `user_id` int(10) unsigned NOT NULL default '0' COMMENT '用户ID', `info` text character set utf8 NOT NULL COMMENT '简介', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='用户信息表
//添加一个user_info 的关联关系 public function relations() { // NOTE: you may need to adjust the relation name and the related // class name for the relations automatically generated below. return array( 'city'=>array(self::BELONGS_TO,'City','city_id'), 'user_info'=>array(self::HAS_ONE,'UserInfo','user_id'), ); }在饥渴式加载中如下使用,with方法中添加一个参数user_info即可
public function actionEager($id){ $id = trim($id); //饥渴式加载 $user = User::model()->with('city','user_info')->findByPk($id); dump($user); }打印结果如下图,可以看到city对象与user_info对象都已经加载到user对象的related属性中了