资讯专栏INFORMATION COLUMN

yii active record多表关联查询的一些细节

Genng / 1825人阅读

摘要:方法返回一个列表,方法永远只返回一个结果。如果有多个结果,则只返回第一个。表的字段可以用从关联的那获得,但那是对象里面的。

表结构

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

array(self::HAS_MANY, "comment", "articleid"),
            "user"=>array(self::BELONGS_TO, "user", "id")
        );
    }
}

comment.php

array(self::BELONGS_TO, "article", "articleid"),
            "replys"=>array(self::HAS_MANY, "reply", "commentid"),
            "user"=>array(self::BELONGS_TO, "user", "id")
        );
    }
}

reply.php

array(self::BELONGS_TO, "user", "id"),
            "comment"=>array(self::BELONGS_TO,"comment","commentid")
        );
    }
}

user.php


查询
符合要求的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 "
"; }

部分字段
$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 "
"; var_dump($article->articleid); var_dump($article->id); var_dump($article->content); echo "
"; foreach ($article->comments as $key => $value) { var_dump($value->commentid); var_dump($value->content); var_dump($value->id); echo "
"; } }


可以看到,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 "
"; }

加载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 "
"; } }


可以看到,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 "
"; } echo "
"; } }


可以看到,只有第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)
至于最后结果能否映射到对象上,或者说映射到对象上对选取的列的字段名有什么要求,本屌没试过,不知道。


以后如果有什么新的发现,会不定期更新此文。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21198.html

相关文章

  • Yii修行之路 - Active Record 活动记录

    摘要:建立关联关系后,通过可以获取一个对象的数组,该数组代表当前客户对象的订单集。定义关联关系使用一个可以返回对象的方法,对象有关联上下文的相关信息,因此可以只查询关联数据。基于表外键定义关联关系是最佳方法。 简介 Yii 在操作数据库方面提供了一个十分强大的类库来支撑整个框架业务的运转,这就是 Active Record (活动记录,以下简称AR)。 基本概念 AR类提供了一个面向对象的接...

    HmyBmny 评论0 收藏0
  • yii2 ActiveRecord多表关联以及多表关联搜索实现

    摘要:今天把这个问题讲明白了,看看是怎么个多表关联以及如何去优化这个关联。现需要在列表展示表的来源渠道,且该渠道可搜索。关联表字段增加查询中的搜索模型也是通过实现的,该模型通过控制着哪个字段可搜索,哪个字段不可搜索。 作者:白狼 出处:http://www.manks.top/yii2_many_ar_relation_search.html 本文版权归作者,欢迎转载,但未经作者同意必须保留...

    venmos 评论0 收藏0
  • YII2中多表关联使用

    摘要:第二个参数是一个数组,其中键为所关联的模型中的属性,值为当前模型中的属性。这里注意中的第二个是指关联的中的,第一个是指中的。 首先先来说明一下表结构 表结构 现在有订单表、用户表、商品清单表、商品库存表 showImg(https://segmentfault.com/img/bVRcME?w=833&h=244); showImg(https://segmentfault.com/i...

    vslam 评论0 收藏0
  • Yii2中hasOne、hasMany以及多对多关联查询用法

    摘要:前言是特有的用于多表关联查询的函数,平时在使用多表关联查询的时候建议使用它们。需求分析使用一条查询语句就能把列表的数据全部展现出来,列表包含一对一,一对多,以及多对多的关系。不能破坏自有的表头排序功能,以及中的存值。相关资料中多表关联查询 前言 hasOne、hasMany是Yii2特有的用于多表关联查询的函数,平时在使用多表关联查询的时候建议使用它们。为什么?因为这种方式关联查询出来...

    qc1iu 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<