表结构
article文章表:aritlceid
,content
,id
(文章发表人的id)
comment评论表:commentid
,content
,id
(评论人的id),articleid
(外键)
reply回复表:replyid
,content
,id
(回复人的id),commentid
(外键)
user用户表:id
,name
关联关系
基于yii 1.16
article->comment->reply,从左到右,两两之间是一对多关系,当然发过来,从右到左是多对一关系。
上面每个表与user之间的关系是多对一关系.
article.php
<?php
class Article extends CActiveRecord{
...
public function tableName()
{
return 'article';
}
public function relations()
{
return array(
'comments'=>array(self::HAS_MANY, 'comment', 'articleid'),
'user'=>array(self::BELONGS_TO, 'user', 'id')
);
}
}
comment.php
<?php
class Comment extends CActiveRecord{
...
public function tableName()
{
return 'comment';
}
public function relations()
{
return array(
'article'=>array(self::BELONGS_TO, 'article', 'articleid'),
'replys'=>array(self::HAS_MANY, 'reply', 'commentid'),
'user'=>array(self::BELONGS_TO, 'user', 'id')
);
}
}
reply.php
<?php
class Reply extends CActiveRecord{
...
public function tableName()
{
return 'reply';
}
public function relations()
{
return array(
'user'=>array(self::BELONGS_TO, 'user', 'id'),
'comment'=>array(self::BELONGS_TO,'comment','commentid')
);
}
}
user.php
<?php
class User extends CActiveRecord{
...
public function tableName()
{
return 'user';
}
}
查询
符合要求的article
所有字段
选取articleid=1的文章
$article=Article::model()->find(array(
'condition'=>'articleid=:articleid',
'params'=>array(':articleid'=>1)
));
foreach ($article as $key => $value) {
var_dump($key);
var_dump($value);
echo "<br>";
}
部分字段
$article=Article::model()->find(array(
'select'=>'content',
'condition'=>'articleid=:articleid',
'params'=>array(':articleid'=>1)
));
选取article及其对应的comment
这里有一对多关联,就不用懒加载
了.
$articles=Article::model()->with(array('comments'))->findAll();
输出
foreach ($articles as $article) {
echo "<br>";
var_dump($article->articleid);
var_dump($article->id);
var_dump($article->content);
echo "<br>";
foreach ($article->comments as $key => $value) {
var_dump($value->commentid);
var_dump($value->content);
var_dump($value->id);
echo "<br>";
}
}
可以看到,active record确实选取了第一篇文章及其下面的5条评论,第二篇文章及其下面的2条评论,以及后面的三篇文章,它们下面没有评论。
findAll()
方法返回一个列表,find()
方法永远只返回一个结果。如果有多个结果,则只返回第一个。with()
方法一次性加载关联
加载article关联的user表
$articles=Article::model()->with(array('user','comments'))->findAll();
输出
foreach ($articles as $article) {
...
var_dump($article->user->name);
echo "<br>";
}
加载comment关联的user表
$articles=Article::model()->with(array('user','comments','comments.user'))->findAll();
这时会出现Syntax error or access violation: 1066 Not unique table/alias: 'user',因为本屌懒,把所有多对一关联都设置成'user'=>array(self::BELONGS_TO, 'user', 'id').
如果comment设置成'comment_user'=>array(self::BELONGS_TO, 'user', 'id')
,查询变成
$articles=Article::model()->with(array('user','comments','comments.comment_user'))->findAll();
就不会报错了.
那么如果不改关联怎么办?
Article::model()->with(array(
'user',
'comments',
'comments.user'=>array('alias'=>'comment_user')))
->findAll();
with()方法也可以像find()方法那样,传入关联数组作为参数。这里为comments.user设置一个别名就行了。
array(
'alias'=>'article',
...
)
选取comment部分字段
前面选取article部分字段时,用的是findAll(array('select'=>'...'))
,这里不能
Article::model()->with(array(
'user',
'comments',
'comments.user'=>array('alias'=>'comment_user')))
->findAll(array(
'select'=>array('comments.content')
));
应该像上面为关联添加别名那样
Article::model()->with(
array('user',
'comments'=>array('select'=>'content'),
'comments.user'=>array('alias'=>'comment_user')
))->findAll();
输出
foreach ($articles as $article) {
...
foreach ($article->comments as $key => $value) {
...
var_dump($value->user->name);
echo "<br>";
}
}
可以看到,comment表的id字段没有值,content有值。
comment表的id字段可以用$value->user->id从关联的user那获得,但那是user对象里面的。
选取comment对应的reply
这下有两个一对多关系了
$articles=Article::model()->with(array(
'user',
'comments'=>array('select'=>'content'),
'comments.user'=>array('alias'=>'comment_user'),
'comments.replys'))
->findAll();
输出
foreach ($articles as $article) {
...
foreach ($article->comments as $key => $value) {
...
foreach ($value->replys as $key => $value) {
var_dump($value->replyid);
var_dump($value->content);
var_dump($value->id);
echo "<br>";
}
echo "<br>";
}
}
可以看到,只有第1,2条评论有回复。
事实上,如果不选取comment部分字段的话,可以直接
$articles=Article::model()->with(array(
'user',
'comments.user'=>array('alias'=>'comment_user'),
'comments.replys'))
->findAll();
加载reply关联的user表
和前面comment关联user一样
Article::model()->with(array(
'user',
'comments'=>array('select'=>'content'),
'comments.user'=>array('alias'=>'comment_user'),
'comments.replys',
'comments.replys.user'=>array('alias'=>'reply_user')))
->findAll();
选取reply部分字段
Article::model()->with(array(
'user',
'comments'=>array('select'=>'content'),
'comments.user'=>array('alias'=>'comment_user'),
'comments.replys'=>array('select'=>'content'),
'comments.replys.user'=>array('alias'=>'reply_user')))
->findAll();
条件查询
选取articleid=1的文章以及其评论,还有对应的回复
Article::model()->with(array(
'user',
'comments.user'=>array('alias'=>'comment_user'),
'comments.replys',
'comments.replys.user'=>array('alias'=>'reply_user')))
->findAll(array(
'condition'=>'articleid=:articleid',
'params'=>array(':articleid'=>1),
'alias'=>'article'
));
这时会报错: Integrity constraint violation: 1052 Column 'articleid' in where clause is ambiguous.还是命名冲突.在findAll()方法的参数里设置article别名,条件列前加上设置好的别名就行了。
Article::model()->with(array(
'user',
'comments.user'=>array('alias'=>'comment_user'),
'comments.replys',
'comments.replys.user'=>array('alias'=>'reply_user')))
->findAll(array(
'condition'=>'article.articleid=:articleid',
'params'=>array(':articleid'=>1),
'alias'=>'article'
));
选取articleid=1且commentid=1的文章以及其评论,还有对应的回复
Article::model()->with(array(
'user',
'comments.user'=>array('alias'=>'comment_user'),
'comments.replys',
'comments.replys.user'=>array('alias'=>'reply_user')))
->findAll(array(
'condition'=>'article.articleid=:articleid and comments.commentid=:commentid',
'params'=>array(':articleid'=>1,':commentid'=>1),
'alias'=>'article'
));
注意,条件是comments.commentid=:commentid
comment,reply分页
和mybatis
一样,只能通过复杂的自定义sql实现,参见本屌的mybatis Result Maps对结果分组3--一对多使用limit.写完那纠结的sql后,调用Article::model()->findBySql($sql,$params)
。
至于最后结果能否映射到对象上,或者说映射到对象上对选取的列的字段名有什么要求,本屌没试过,不知道。
以后如果有什么新的发现,会不定期更新此文。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。