2013-02-21 137 views
2

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

例 我已经定义AR类邮政用户注释 * 邮政 *有关系所有者(belongs_to的)到类用户和关系评论(HAS_MANY)到类评论

我有一个数组的对象的$帖子。 对于不同的原因,$帖子不能从一开始初始化

'with' => array('owner', 'comments') 

如果我这样做:

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

$发布查询对子级的retriving 所有人提出和查询评论。 这可能会导致大量查询和脚本执行缓慢。 更好的方法是在一个步骤中读取一种类型的所有相关对象。

难道这样的事情存在retriving有一定关系的所有相关对象为对象的数组?:

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

我需要这个形式给出的几个原因:

  1. 有时我不能提前告诉我是否需要关系初始化。
  2. 在“父母”之后阅读相关对象可能会快得多,因为连接速度可能会很慢。
  3. 缓存可能会受到影响,因为有时候“父”对象不能与相关对象具有相同的缓存时间,因此,在从缓存中提取父对象后,以分组/批量方式读取相关对象可能是有用的。例如:$ post已被缓存,但我无法缓存最后3条评论和帖子。

yii是否包含这样的东西?或者可以帮助的插件?

谢谢

+0

这是什么原因,当初始化'$ posts'数组时,你不能指定'with'? – dInGd0nG 2013-02-22 05:42:37

+0

@ dInGd0nG我有三个主要原因: 1.性能。我有很多关系的对象。如果我使用“with”加入它们,则可能会导致查询速度很慢且很慢。 2.遗留代码。作为一个函数的结果,我有对象的父对象(在示例$ posts中)。将相关对象附加到结果上会更方便,而不是修改该函数(这可能导致破坏代码的其他部分)。 3.灵活性。我不会被迫事先考虑我需要什么样的关系,我可以轻松地(并且减少数据库压力)将关系附加到一组父对象上。 – humeniuc 2013-02-22 07:15:55

回答

0

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

比方说comment有一个post_id,它链接到post表中的id

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

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

  1. 迭代给定$posts和存储后id S IN的列表。运行SQL查询SELECT * FROM comments WHERE post_id IN ([the IDs from the list])
  2. 将结果合并到您的$posts中。

选项2:要修复可能的IN子句限制,请改用JOIN。

  1. 运行一个SQL查询,如SELECT * FROM comments JOIN [the SELECT query for the posts]

选项3(我的首选):根据您的使用情况下,它可能是最干净的,只是重装意见和作者的所有帖子(在posts模型上criteria定义with)。

  1. 添加条件withif ($loadDetails) { criteria->'with' => array('owner', 'comments'); }
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

希望这回答了你的查询。

+0

该程序是我需要的反例。我不能和一起使用。在简单的帖子和评论的例子中,如果我需要显示100个帖子,并且每个人都有200个评论,那么with +会一起创建一个生成2000行的查询。在实际应用中,这个过程可能会导致非常缓慢的查询 – humeniuc 2013-02-28 04:24:55

+0

我有点困惑。 – 2013-02-28 07:48:49

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)。但是,如果您在单个页面上加载了许多帖子+评论,则会在错误的位置进行优化。

你有几件事情在我看来担心DB查询大小之前实现:

  1. 不要加载评论正在直至需要它们,这是在点击一个按钮,滚动到该帖子'标题或简单地逐渐下到页面,直到完成。这样,服务器一次只查找一篇文章的评论,而用户甚至不希望看到帖子编号为99的评论。

  2. 不要每页加载100篇文章,除非它们非常小帖子(在这种情况下,有什么担心)。再次进行滚动会有所帮助,或者甚至可以帮助您进行滚动,或者甚至可以帮助您进行滚动,或者甚至可以帮助您进行滚动,或者甚至可以不用100个用户希望看到的帖子,如果有200条评论,有多少用户会阅读10条以上?

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

然而

如果你真的需要担心20 000行,ActiveRecord的实例应该是您第一个雷达。在任何正常的设置中,20 000行是无需担心的,但即使在更高规格的系统上,也有20 000行活动记录对象。如果你正在处理非常大的和/或复杂的数据集,你应该使用DAO。

+0

与帖子,评论,用户的情况纯粹是示范。返回的结果数量相同,因此不是页面结构,加载程序等是问题。 Hoever感谢您对不使用ActiveRecord的消解。看起来AR是为了简单的任务而设计的。 Yii在他们的AR中没有'post对象初始化批量初始化关系'功能是一个耻辱。 – humeniuc 2013-03-02 19:43:13

+0

这真是一个耻辱,但如果你写了一个,分享它,它可能会进入Yii 2.0:p – Paystey 2013-03-02 22:39:31