您的位置:首页 > 编程语言 > PHP开发

Yii框架relations的使用

2015-09-15 23:30 651 查看
通过在 relations() 中声明这些相关对象,我们就可以利用强大的 Relational ActiveRecord (RAR) 功能来访问资讯的相关对象,例如它的作者和评论。不需要自己写复杂的 SQL JOIN 语句。

前提条件

在组织数据库时,需要使用主键与外键约束才能使用ActiveReocrd的关系操作;

场景

申明关系

两张表之间的关系无非三种:一对多;一对一;多对多; 在AR中,定义了四种关系:

关系                              定义
BELONGS_TO              A和B的关系是一对多,那么B属于A
HAS_MANY                A和B之间的关系是一对多,那么A有多个B
HAS_ONE                 这是HAS_MANY的一种特殊情况,A至多有一个B
MANY_MANY               这个对应多对多的情况,在AR里会将多对多以BELONGS_TO和HAS_MANY的组合来解释


在AR中通过重写CActiveRecord类的relations()方法来申明关系;这个方法返回一个关系配置的数组;一个数组无素代表一个单独的关系,格式如下:

‘VarName’=>array(‘RelationType’,’ClassName’,’ForeignKey’, …additional options)

Var Name                关系名
Relation Type           四种关系:self::BELONGS_TO, self::HAS_ONE, self::HAS_MANY, self::MANY_MANY
Class Name              代表当前AR类要关联的那个AR类名
Foreign Key             实现关系的外键, 有可能有多个,即列名


‘select’: string|array, 被选中的列列表。默认值为 ‘*’,这意味着是所有列。 如果它们出现在一个表达式中(例如: COUNT(relationName.name) AS name_count)。

‘condition’: string, WHERE子句。 默认值为空。 注意,列引用需要加入’relationName’前缀 。(例如:relationName.age>20)

‘order’: string, ORDER BY子句。 默认值为空。 注意,列引用需要加入’relationName’前缀 。(例如:relationName.age DESC)

‘with’: string|array, 应该与这个对象一起装载的子对象相关名单。 注意,这仅仅是延迟加载,而不是预先加载。

‘joinType’: 联接类型。 默认值为‘LEFT OUTER JOIN’。

‘alias’: 关系与关联表的别名。 它默认为null, 意味着表的别名与关系名称相同。

‘params’: 参数绑定到要生成的SQL语句上。 这应作为名称-值的数组。

‘on’: ON 子句。 此处指定的条件将追加到使用 AND 运算符的联接条件。

‘index’: 其值应作为存储相关的对象的数组的键的列的名称。 此选项仅适用于, HAS_MANY 和 MANY_MANY 关系。

‘scopes’: 应用范围。在单一的范围情况下可以像’scopes’=>’scopeName’, 在多个作用域范围情况下可以使用数组像这样’scopes’=>array(‘scopeName1’,’scopeName2’)。

延迟加载时有一定的关系,下列选项可用:

‘group’: string, GROUP BY子句。 默认值为空。 注意,列引用需要加入’relationName’前缀 。(例如: relationName.age)。此选项仅适用于HAS_MANY 和 MANY_MANY 关系。

‘having’: string, HAVING子句。 默认值为空。 注意,列引用需要加入’relationName’前缀 。(例如: relationName.age)。此选项仅适用于HAS_MANY 和 MANY_MANY 关系。

‘limit’: 数据行的limit选择。 这个选项不能应用到BELONGS_TO。

‘offset’: 数据行的偏移量。 这个选项不能应用到BELONGS_TO。

‘through’: 获取相关的数据时将用作桥的模型的关系的名称。可以设置仅为 HAS_ONE 和 HAS_MANY。

return array(
'reply' => array(self::BELONGS_TO, 'BookPostReply', 'postid'),//连接BookPostReply表
);


self::BELONGS_TO默认是用当前指定的键跟关联表的主键进行join

默认生成的sql是 on id = postid,id是BookPostReply的主键。

需要生成 on BookPostReply.postid = t.postid,不去关联主键,而且关联其中一个字段的值

return array(
'reply' => array(self::BELONGS_TO, 'BookPostReply', '', 'on' => 't.postid=reply.postid'),
);


关联中的东西也可以有order的

'imgs'=>array(self::HAS_MANY,"LightProImgs","pid","order"=>"imgs.paixu desc","limit"=>3)


多表关联的实际应用:

1,首先多表关联是在models/xx.php的relations里配置的。而且是互配,但有区别。

格式:

‘VarName’=>array(‘RelationType’, ‘ClassName’, ‘ForeignKey’, …additional options)

需要弄清楚的几点:

1,VarName指什么? 详见下面例2。

2,RelationType。一共有4种,分别为self::HAS_MANY, self::BELONGS_TO, self::MANY_MANY, self::HAS_ONE。

3,ClassName。即关联的另一个../model/类名.php。

4,ForeignKey。谁是谁的外键?写了是用主键关联,为空两个表不是用主键关联需要on

5,附加条件

两个表不是用主键关联

‘user’ => array(self::BELONGS_TO, ‘OaskUser’, ” ,’on’=>’name=userName’ , ‘select’=>’TrueName’, ‘order’=>’sort asc’),

'varchar'=>array(self::HAS_ONE, 'CustomerEntityVarchar', 'entity_id','select'=>'varchar.value','on'=>'varchar.attribute_id="831"'),


BELONGS_TO(属于): 如果表 A 和 B 之间的关系是一对多,则 表 B 属于 表 A ;

HAS_MANY(有多个): 如果表 A 和 B 之间的关系是一对多,则 A 有多个 B ;

HAS_ONE(有一个): 这是 HAS_MANY 的一个特例,A 最多有一个 B ;

MANY_MANY: 这个对应于数据库中的多对多关系。 由于多数 DBMS 不直接支持 多对多 关系,因此需要有一个关联表将多对多关系分割为一对多关系。在 AR术语中,我们可以解释 MANY_MANY 为 BELONGS_TO 和 HAS_MANY 的组合。

STAT :除了上述的关系类型,一个特殊的关系,称为STAT也支持 可用于进行统计查询(或聚合查询) 。 检索聚合对相关对象的信息,如数量。如 一篇日志共有多少个评论

'detailCounts' => array(self::STAT, 'PurchaseDetail', 'purchase_hid'),


例1,一对多关系 (post和user之间的关系)

(1)models/Post.php

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)'),
);
}
}


其中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', 'author_id'),
);
}
}


对于User,与Post的关系是属于HAS_MANY(一对多)关系。并通过Post的author_id与Post关联。 由于两者是一对多关系,所以要用posts

例2,多对多关系。中间表名( 本表外键, many表外键 )

在FailParts.php中

'Users' => array(self::MANY_MANY, 'User', '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’, ‘ForeignKey’, …additional options)

其中VarName与B基本相同。但未必完全一样。此时就可以在A的views/A/xx.php中通过VarName来访问B及其属性值了。

如果是一对一/一对多:A->VarName->name

如果是多对多:

$users = As->VarName
foreach($users as $u){
$_tmp_users[] = $u -> getName;
}
userStr = implode(', ', $_tmp_users);


懒惰式加载(lazy loading,也可译为 迟加载) 方式

// 获取 ID 为 10 的帖子
$post=Post::model()->findByPk(10);
// 获取帖子的作者(author): 此处将执行一个关联查询。
$author=$post->author;


懒惰式加载用起来很方便,但在某些情况下并不高效。

渴求式加载(eager loading)方式。$posts=Post::model()->with(‘author’,’categories’)->findAll();

AR scopes

//SchoolDepartment::model()->allDepartmentAndClass($id)->findAll();
public function relations() {
return array(
'class' => array(self::HAS_MANY, 'SchoolClass', 'school_department_id'),
);
}

public function scopes() {
return array(
'allDepartmentAndClass',
);
}

public function allDepartmentAndClass($id) {
$this->getDbCriteria()->mergeWith(array(
'with' => "class",
'condition' => "t.tbl_school_id=$id",
));
return $this;
}


强制查询使用join连接查询

$criteria->together = true;


下面介绍是一种“急切导入”方法:在使用find和findAll时,使用with()方法,例:

$posts=Post::model()->with('author')->findAll()
$posts=Post::model()->with('author')->findAll()


这样就可以在一次查询时连同查询其他信息了;with方法可以接受多个关系:

$posts=Post::model()->with('author','categories')->findAll();
$posts=Post::model()->with('author','categories')->findAll();


这样就可以将作者和类别的信息一并进行查询;同样,with还支持多重急切导入

$posts=Post::model()->with( 'author.profile', 'author.posts', 'categories')->findAll();


/article/9033234.html

/article/3952942.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: