4.2 关联查询
关于ThinkPHP的关联查询支持。
目前支持的表间关联方式包括三种:
- 1、ONE_TO_ONE ( 包括HAS_ONE 和 BELONGS_TO )2、ONE_TO_MANY( 包括HAS_MANY 和 BELONGS_TO)3、MANY_TO_MANY
Dao类增加了一个xfind() 方法用于直接获取带关联记录的返回结果,而 getRelation() 方法用于获取已经返回记录的关联记录(集)。
xfind的参数和find方法保持不变,区别在于xfind方法会一起返回关联记录,而find方法默认不返回关联记录。
find方法最后增加了一个relation参数,用以控制是否进行关联查询。 xfind方法仅仅是find方法的一个引用。relation参数支持false(不进行关联查询)、true(进行所有关联查询)和array(只查询某个关联)。
举例:
- $dao->find("id=2"); // 返回id为2的记录$dao->xfind("id=2"); // 返回id为2的记录,并同时返回其关联记录(如果有定义)
如果不是使用find方法进行查询,可以配合getRelation方法进行关联记录的查询。
例如:
- $user = $dao->getById($id);$user = $dao->getRelation($user);// 或者使用下面的方法$user = $dao->getById($id,'','*','',true);
同样,增加了xFindAll方法进行关联查询(返回Volist对象),而findAll方法默认不进行关联查询。
例如:
- $list = $dao->findAll("type=1"); //查询type为1的用户$list = $dao->xFindAll("type=1"); // 查询并返回关联记录
关联查询需要Vo类定义_link 属性配合,例如UserVo中定义如下关联信息:
- var $_link = array(
-
// 每个用户都有一个个人档案-
array( 'mapping_type'=>HAS_ONE,-
'class_name'=>'Profile',-
'foreign_key'=>'userId',-
'mapping_name'=>'profile',- ),
-
// 每个用户有多个文章-
array( 'mapping_type'=>HAS_MANY,-
'class_name'=>'Article',-
'foreign_key'=>'userId',-
'mapping_name'=>'articles',-
'mapping_order'=>'cTime desc'),-
// 每个用户都属于一个部门-
array( 'mapping_type'=>BELONGS_TO,-
'class_name'=>'Dept',-
'foreign_key'=>'userId',-
'mapping_name'=>'dept'),-
// 每个用户可以属于多个组,每个组可以有多个用户-
array( 'mapping_type'=>MANY_TO_MANY,-
'class_name'=>'Group',-
'mapping_name'=>'groups',-
'foreign_key'=>'userId',-
'relation_foreign_key'=>'goupId',-
'relation_table'=>'think_gourpUser')- );
而getRelation方法,则用于获取已经查询到的Vo对象的某个关联记录
- $vo = $dao->getRelation($vo,HAS_MANY,'articles');
关于映射关系的定义,还有一些高级默认规则,除了mapping_type、class_name 和mapping_name 三个属性必须外,其他都是可选的。另外,还可以包括mapping_order、condition、mapping_limit等高级属性。
默认规则
外键的默认规则是当前Vo对象名称+id,例如:
UserVo对应的可能是表think_user (注意:think只是一个表前缀,可以随意配置)
那么think_user表的外键默认为 user_id,如果不是,就必须在定义表间映射关系的时候定义 foreign_key 。
同样的道理,对于多对多的情况,relation_foreign_key 的规则相同。
多对多的中间表默认表规则如下:
如果think_user 和 think_group 存在一个对应的中间表,默认的表名应该是
如果是由group来操作关联表,中间表应该是 think_group_user,如果是从user表来操作,那么应该是think_user_group,也就是说,多对多关联的设置,必须有一个Vo类里面需要显式定义中间表,否则双向操作会出错。
中间表无需另外的id主键(但是这并不影响中间表的操作),通常只是由 user_id 和 group_id 构成。
另外一个潜规则,因为表间映射关系可以定义condition属性,通常都是通过外键来获取关联数据,但是如果你定义了condition属性,那么就会重新使用condition的条件来获取关联表的数据。
在HAS_MANY 和MANY_TO_MANY情况下,可以使用mapping_order 和 mapping_limit 进行记录的排序和获取部分数据。HAS_ONE 和 BELONGS_TO 永远都只会返回最多一条记录。
另外除了MANY_TO_MANY之外,其他映射关系可以使用 mapping_fields 来返回你需要的关联表字段。
关于自引用关联
如果Vo类的_link属性里面对于 class_name 为自身的情况就属于自引用关联。
通常用于从属关系的关联,例如,某个用户是另外一个用户的领导,某个节点下面有多个子节点这样的应用情况。
对于这样的情况,ThinkPHP增加了一个parent_key属性来定义,该属性在自引用方式下面有效。例如NodeVo中有如下定义:
- //每个节点具有多个子节点
- var $_link = array(
- array(
'mapping_type'=>HAS_MANY,-
'class_name'=>'Node',-
'foreign_key'=>'id',-
'parent_key'=>'pid',-
'mapping_name'=>'sub',-
'mapping_order'=>'seqNo asc'),- );
parent_key 默认名称为parent_id,如果不是则需要指定。