在父对象初始化之后初始化相关对象

时间:2013-02-21 18:49:08

标签: php activerecord yii

我有一个同一类的Active Record对象数组。 该对象具有已定义的关系。 在“父”对象初始化之后,有没有办法以“批量”方式读取相关对象?

实施例 我已经定义了AR类发布用户评论 * 发布 *将所有者(BELONGS_TO)与用户类关联,并将评论(HAS_MANY)与评论

我有一个数组 $ posts 发布的对象。 由于不同的原因,无法从

开始初始化 $ posts
'with' => array('owner', 'comments')

如果我这样做:

foreach ($posts as $post) {
   var_dump($post->owner);
   var_dump($post->comments);
}

对于每个 $ post ,可以查询所有者的查询以及重新评论的查询。 这可能导致大量的查询和慢速执行。 更好的方法是一步读取一种类型的所有相关对象。

对于一个对象数组,是否存在类似于某种关系的所有相关对象?:

Post::readRelatedObject($posts, 'owner'); 
Post::readRelatedObject($posts, 'comments');

出于以下几个原因,我需要这个方法:

  1. 有时我无法提前告诉我是否需要初始化关系。
  2. 在“父母”之后阅读相关对象要快得多,因为连接可能会很慢。
  3. 缓存可能会受到影响,因为有时“父”对象与相关对象的缓存时间不同,因此在从缓存中提取父对象之后,以分组/批量方式读取相关对象可能很有用。例如: $ post 已缓存,但我无法在帖子中缓存最后3条评论。
  4. yii是否包含这样的内容?还是一个可以提供帮助的插件?

    谢谢

3 个答案:

答案 0 :(得分:2)

如果您正在尝试针对这样的大型结果集进行优化,那么您几乎总是更喜欢自己滚动。 Yii开发人员even recommend没有使用activerecord来处理这种复杂情况(非常不同的加载顺序)。

虽然

首先,我建议根据您检索的所有帖子的ID建立自己的CDBCriteria。如果你在Posts模型中执行此操作,它也可以很好地(显然不完美)与为关系定义的标准绑定。

static public function loadComments(array $ids)
{
    $crit = Comment::model()->dbCriteria;
    $crit->addInCondition('post_id', .....

    .....
    return Comment::model()->findAll($crit);
}

这会给你所有关于这组ID的评论,你甚至可以做一些额外的处理,用它们所属的帖子ID来索引它们。

但是,真的

在你的评论中,你说这100个帖子,每个200条评论可能意味着加载2000(实际上是20 000)。但是如果你在一个页面上加载了很多帖子+评论,你就会在错误的地方进行优化。

在我看来担心数据库查询大小之前,您需要执行一些操作:

  1. 在需要之前不要加载评论,只需单击按钮,滚动到该帖子的标题,或者只是逐步向下翻页直到完成。这样,服务器一次只查找一个帖子的评论,用户甚至可能不希望看到第99号帖子的评论。

  2. 每页不要加载100个帖子,除非它们是非常小的帖子(在这种情况下,有什么担心)。逐步滚动将有助于,甚至pagination

  3. 过滤您的搜索结果只会显示相关内容,很可能不会有100个用户想看到的帖子,如果有200条评论,有多少用户会阅读超过10条?

  4. 如果你实现其中的一个,我认为结果集大小的问题将会消失。

    然而

    如果确实确实需要担心20 000行,那么ActiveRecord实例化应首先在您的雷达上。在任何正常设置中都不用担心20 000行,但即使在更高规格的系统上,也肯定会有20 000个活动记录对象。如果你正在处理非常大和/或复杂的数据集,你应该使用DAO。

答案 1 :(得分:0)

我不知道可以做到这一点的扩展。也许你可以创建一个yii应该知道有关数据的一切来解决这个任务。

假设comment有一个post_id链接到id表格中的post

有几个选项可以加载帖子的相关评论。

选项1 :使用ID查询所需的评论。某些DBMS限制了SQL查询的长度,因此您可能必须小心并且不要在IN子句中放置许多ID。也许这必须分成多个查询。

  1. 迭代给定的$posts并将帖子id存储在列表中。
  2. 运行SELECT * FROM comments WHERE post_id IN ([the IDs from the list])
  3. 之类的SQL查询
  4. 将结果合并到$posts
  5. 选项2 :要修复可能的IN子句限制,请改用JOIN。

    1. 运行SELECT * FROM comments JOIN [the SELECT query for the posts]之类的SQL查询。
    2. 选项3 (我的首选):根据您的使用情况,最简单的方法是重新加载包含评论和作者的所有帖子(通过在{{1}上定义withcriteria模型中)。

      1. 添加条件postswith

答案 2 :(得分:0)

如果您主要关注的是避免延迟加载,并希望检索所有帖子及其相关的所有者和评论记录。

这对你有用。

$criteria = new CDbCriteria();
$criteria->with = array('comments','owner');
$result = $Post->together()->findAll($criteria);

参考: http://www.yiiframework.com/doc/api/1.1/CActiveRecord#together-detail http://www.yiiframework.com/doc/api/1.1/CDbCriteria#with-detail

希望这可以回答您的问题。