2010-02-22 61 views
11

我有一个CakePHP 1.3应用程序,并且非常喜欢Containable behavior来获取数据。CakePHP模型:COUNT(*)in Containable

让我们假设我有帖子与评论的一对多关系。我使用Containable查询(分页)所有帖子和所有者注释的列表。但我只对每个帖子有多少评论感兴趣。我没有找到任何方式来实现这个查询与含有不含所有行的评论。我试过了:

$this->paginate=array(
      'fields' => 'Post.title, Post.created', 
      'contain' => array('Comment'=>'COUNT(*) AS count'), 
     ); 

结果'模型'注释'与模型没有关联'计数''的错误信息。

$this->paginate=array(
      'fields' => array('Post.title, Post.created'), 
      'contain' => array('Comment'=>array('fields'=>'COUNT(*) AS count'), 
     ); 

不起作用,每个帖子的结果集包含一个空的评论阵列除了最后一个,它包含了数场,但具有所有评论不只是属于那些数量。

我其他的猜测是

$this->paginate=array(
      'fields' => 'Post.title, Post.created, COUNT(Comment.id)', 
      'contain' => array('Comment'=>array('fields'=>''), 
     ); 

但这会导致一个错误,因为的hasMany关系是独立询问,所以回答表是不是在查询后条目。 如何计算邮寄的评论数量?

回答

11

好,要做到这一点的最好办法是建立一个名为comment_count场在posts表,这个键添加到注释模型$属于关联帖子阵列:

'counterCache' => true

每次什么东西会随着评论的发生,相关文章中的comment_count字段将被更新(实际上,它每次都会重新计算,而不仅仅是添加或删除)。

它更好,因为当你为用户提取数据时,它的速度更快,甚至不会触及评论表。由于您使用的是可容忍的行为,我想速度和轻量级就是您要找的。

+3

这是一个不错的主意,但它不能解决更复杂的查询问题,即保持与行关联的计数不起作用(例如用户选择某些条件的报告系统)。有没有其他方法可以使用容易获得计数? – Zxaos 2011-09-15 18:11:05

6

我有同样的问题。 PawelMysior给出的答案很好,并导致了解决方案。

我在CakePHP书中找到了更多的细节:3.7.4.1.1 counterCache - Cache your count()。这很有帮助,但仍有点模糊。为了其他人的缘故,我想提供一些进一步的细节。

我有两个表:Post和Image。当我向帖子添加图片时,我想跟踪每篇帖子在帖子索引列表中显示的图片数量,而无需在图片表上运行额外的计数查询。

CREATE TABLE posts 
(
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, 
user_id INTEGER UNSIGNED NOT NULL, 
title VARCHAR(255), 
body TEXT, 
created DATETIME, 
modified DATETIME, 
image_count INTEGER UNSIGNED, 
PRIMARY KEY (id) 
) ENGINE=InnoDB; 

CREATE TABLE images 
(
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, 
post_id INTEGER UNSIGNED NOT NULL, 
filename VARCHAR(255), 
created DATETIME, 
modified DATETIME, 
PRIMARY KEY (id) 
) ENGINE=InnoDB; 

注意,image_count云在posts表。 images表中没有什么特别的。

class Post extends AppModel 
{ 
    var $name = 'Memory'; 
    var $hasMany = array(
     'Image' => array(
      'className' => 'Image', 
      'foreignKey' => 'post_id', 
      'dependent' => false 
     ) 
    ); 
} 

class Image extends AppModel 
{ 
    var $name = 'Image'; 
    var $belongsTo = array(
     'Post' => array(
      'className' => 'Post', 
      'foreignKey' => 'post_id', 
      'counterCache' => true 
     ) 
    ); 
} 

注意counterCache被添加到Image模型。 Post模型没有什么特别的。

$this->Post->Behaviors->attach('Containable'); 
$post = $this->Post->find('all', array(
    'conditions' => array('user_id' => 7), 
    'order' => array('Post.created DESC'), 
    'contain' => array(
     'Post' => array(
      'User' => array('first_name', 'last_name') 
     ) 
    ) 
)); 

现在,当我们做一个find没有必要做任何特殊找到计数,因为它会自动在Post结果的字段。请注意下面的image_count

Array 
(
[Post] => Array 
     (
      [0] => Array 
       (
        [id] => 14 
        [user_id] => 7 
        [title] => Another great post 
        [body] => Lorem ipsum... 
        [created] => 2011-10-26 11:45:05 
        [modified] => 2011-10-26 11:45:05 
        [image_count] => 21 
        [User] => Array 
        (
         [first_name] => John 
         [last_name] => Doe 
        ) 
       ) 
     ) 
) 

有一点需要注意,如果你添加counterCache到现有的数据库结构,在Post计数为零,直到另一个Image加入。此时,CakePHP将执行实际计数并将image_count更新为正确的数量。

我希望这个额外的信息对某人有帮助。