PHP编程:详解YII关联查询
《详解YII关联查询》要点: PHP应用一、多表关联的配置 在我们使用 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() 办法.此办法返回一个关系配置数组.每个数组元素通过如下格式表示一个单一的关系. 'VarName'=>array('RelationType','ClassName','ForeignKey',...additional options) 其中 VarName 是关系的名字;RelationType 指定关系类型,可以是一下四个常量之一: self::BELONGS_TO,self::HAS_ONE,self::HAS_MANY and self::MANY_MANY;ClassName 是此 AR 类所关联的 AR 类的名字; ForeignKey 指定关系中使用的外键(一个或多个). 必要弄清楚的几点: (1),VarName指什么? 详见下面例2. (2),RelationType.一共有4种,分别为 self::HAS_MANY,self::BELONGS_TO,self::MANY_MANY,self::HAS_ONE. (3),ClassName.即关联的另一个../model/类名.php. (4),ForeignKey.谁是谁的外键? (5),附加条件 ER Diagram 例1,一对多与多对一关系(post和user之间的关系) 1)models/Post.php class Post extends CActiveRecord { ...... public function relations() { return array( 'author'=>array(self::BELONGS_TO,'User','author_id'),); } } 其中Post与User的关系是BELONGS_TO(多对一)关系,并通过Post的author_id与User关联. Post中author_id是外键,关联到User中. 注:此处的VarName是author,一个对象. (2)models/User.php class User extends CActiveRecord { ...... public function relations() { return array( 'posts'=>array(self::HAS_MANY,'Post','profile'=>array(self::HAS_ONE,'Profile','owner_id'),); } } 对于User,与Post的关系是属于HAS_MANY(一对多)关系.并通过Post的author_id与Post关联. 例2,多对多关系 在FailParts.php中 'Users' => array(self::MANY_MANY,'fail_parts_user(fail_parts_id,user_id)'), 在User.php中 'FailParts' => array(self::MANY_MANY,'FailParts','fail_parts_user(user_id,fail_parts_id)'), 由于两者是多对多关系,所以要用Users,而不是User;要用FailParts,而不是FailPart. 此处的Users和FailParts,即为前面的VarName. 例3,一对一关系 比拟简单,暂略. 2,关于VarName. 对于类A.php,'VarName'=>array('RelationType','B',...additional options) 如果是一对一:A->VarName foreach($posts as $u){ $_tmp_titles[] = $u -> title; } titleStr = implode(',',$_tmp_titles); 二、多表关联的使用 常常在controllers里 1,延时加载 (1)多对一 $post = Post::model()->findByPk(10); 批注:此处本色是一对一. (2)一对多 $user = User::model()->findByPk(10); (3)多对多 必要重点注意:两个id有先后关系. 站在$repairInfo实例的角度,关联关系必需是 'FailParts' => array(self::MANY_MANY,'repair_mapping(repair_info_id, 而站在$failParts实例的角度,则关联关系变为 'RepairInfos' => array(self::MANY_MANY,'RepairInfo','repair_mapping(fail_parts_id,repair_info_id)'), 而前面也已经指出,不必要双方都配置,只需必要的一方设置即可. 之前曾使用过的笨办法: /*办法一:使用表关系(多对多)*/ $fails = $repairInfo->FailParts;//在$repairInfo中使用 /*办法二:使用原始办法*/ $id = $repairInfo->id; $maps = RepairMapping::model()->findAll("repair_info_id = $id"); $f_ids = array(); foreach($maps as $map){ array_push($f_ids,$maps[0]->fail_parts_id); } $f_idsStr = implode(',$f_ids); $fails = FailParts::model()->findAll("id IN ($f_idsStr)"); 2,主动加载――with (1)一对多 $posts = Post::model()->('author')->findAll(); 例子: User.php //查询一个机房$idc_id的所有用户 function getAdminedUsersByIdc($idc_id){ $c = new CDbCriteria(); $c->join = "JOIN idc_user on t.id=idc_user.user_id"; $c->condition = "idc_user.idc_id=$idc_id"; return User::model()->with('Idcs')->findAll($c); } //规则中配置 'Idcs' => array(self::MANY_MANY,'Idc','idc_user(user_id,idc_id)'), 批注:没有with('Idcs'),执行后的结果也一样.只不过不再是eager loading. 三、带参数的关联配置 常见的条件有 1,condition 按某个表的某个字段加过滤条件 例如: //在User的model里定义,如下关联关系 'doingOutsources' => array(self::MANY_MANY,'Outsource','outsource_user(user_id,outsource_id)','condition' => "doingOutsources.status_id IN(" . Status::ASSIGNED . "," . Status::STARTED ."," . Status::REJECTED .")"), //结论:condition是array里指定model的一个字段. 显然,doingOutsources是真实数据表Outsource的别名,所以在condition中可以使用doingOutsources.status_id,当然也可以使用Outsource.status_id.另本表名user的默认别名是t. 2,order 按某个表的某个字段升序或降序 //在RepairInfo的model里定义,如下关联关系 'WorkSheet' => array(self::HAS_MANY,'WorkSheet','repair_info_id',order => 'created_at desc'),//调用 $worksheets = $repair_info->WorkSheet; //此时$worksheets是按降序排列 //结论:order是array里指定model的一个字段. with 还有用于lazy loading的 四、静态查询(仅用于HAS_MANY和MANY_MANY) 关键字:self:STAT 1,基本用法.例如, class Post extends CActiveRecord { ...... public function relations() { return array( 'commentCount'=>array(self::STAT,'Comment','post_id'),'categoryCount'=>array(self::STAT,'Category','post_category(post_id,category_id)'); ); } } 2,静态查询也支持上面的各种条件查询 'doingOutsourceCount' => array(self::STAT,'condition' => "outsource.status_id IN(" . Status::ASSIGNED . ", 其他查询还包含 condition 使用较多 order 3,静态查询的加载方式 可以使用lazy loading方式 两者的性能比拟: 如果必要取所有post的所有comment,前者必要2N+1次查询,而后者只有一次.两者的选择视情况而定. 编程之家培训学院每天发布《详解YII关联查询》等实战技能,PHP、MYSQL、LINUX、APP、JS,CSS全面培养人才。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |