【问题标题】:Paginate results filtered by condition on associated model (HABTM) using Containable使用 Containable 按关联模型 (HABTM) 上的条件过滤结果分页
【发布时间】:2011-10-02 01:14:00
【问题描述】:

我需要对属于特定Category(HABTM 关联)的Products 列表进行分页。

在我的Product 模型中,我有

var $actsAs = array('Containable');
var $hasAndBelongsToMany = array(
    'Category' => array(
        'joinTable' => 'products_categories'
    )
);

ProductsController

$this->paginate = array(
    'limit' => 20,
    'order' => array('Product.name' => 'ASC'),
    'contain' => array(
        'Category' => array(
            'conditions' => array(
                'Category.id' => 3
            )
        )
    )
);
$this->set('products', $this->paginate());

但是,生成的 SQL 如下所示:

SELECT COUNT(*) AS `count` 
FROM `products` AS `Product` 
WHERE 1 = 1;

SELECT `Product`.`*` 
FROM `products` AS `Product` 
WHERE 1 = 1 
ORDER BY `Product`.`name` ASC 
LIMIT 20;

SELECT `Category`.`*`, `ProductsCategory`.`category_id`, `ProductsCategory`.`product_id` 
FROM `categories` AS `Category` 
JOIN `products_categories` AS `ProductsCategory` ON (`ProductsCategory`.`product_id` IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) AND `ProductsCategory`.`category_id` = `Category`.`id`)
WHERE `Category`.`id` = 3

(即选择 20 个Products,然后查询他们的Categories

虽然我需要

SELECT COUNT(*) AS `count` 
FROM `products` AS `Product` 
JOIN `products_categories` AS `ProductsCategory` ON `ProductsCategory`.`product_id` = `Product`.`id`
JOIN `categories` AS `Category` ON `Category`.`id` = `ProductsCategory`.`category_id`
WHERE `Category`.`id` = 3;

SELECT `Product`.*, `Category`.*
FROM `products` AS `Product` 
JOIN `products_categories` AS `ProductsCategory` ON `ProductsCategory`.`product_id` = `Product`.`id`
JOIN `categories` AS `Category` ON `Category`.`id` = `ProductsCategory`.`category_id`
WHERE `Category`.`id` = 3
ORDER BY `Product`.`name` ASC 
LIMIT 20;

(即选择属于Category的前20个Productsid = 3)

注意: 没有Containable 的可能解决方案是(如Dave 建议的那样)使用连接。 This 帖子提供了一个非常方便的助手来构建 $this->paginate['joins'] 以对 HABTM 关联进行分页。

注意:仍然在寻找使用Containable 比伪造hasOne 绑定更优雅的解决方案。

【问题讨论】:

    标签: cakephp cakephp-1.3 has-and-belongs-to-many pagination containable


    【解决方案1】:

    我终于找到了一种方法来做我想做的事,所以把它发布为答案:

    Containable - you've got to use fake hasOne association 中强制JOIN(并能够通过关联模型上的条件进行过滤)。

    就我而言,ProductsController 中的代码应该是:

    $this->Product->bindModel(array('hasOne' => array('ProductsCategory')), false);
    
    $this->paginate = array(
        'limit' => 20,
        'order' => array('Product.name' => 'ASC'),
        'conditions' => array(
            'ProductsCategory.category_id' => $category
        ),
        'contain' => 'ProductsCategory'
    );
    
    $this->set('products', $this->paginate());
    

    注意 false 作为 bindModel 的第二个参数 - 这使得绑定持久化。这是必需的,因为paginate()find('all') 之前发出find('count'),这将重置临时绑定。所以你可能想在之后手动unbindModel

    此外,如果您的条件在 HABTM 关联模型中包含多个 ID,您可能希望将 'group' => 'Product.id' 添加到您的 $this->paginate[] 中(如 Aziz 在他的回答中所示)以消除重复条目(仅适用于 MySQL)。

    更新: 但是,与连接方法相比,这种方法有一个严重的缺点(Dave 建议):条件只能适用于中间模型的外键(在我的情况下为category_id);如果您想在关联模型中的任何其他字段上使用条件 - 您可能必须添加另一个 bindModel('hasOne'),将中间模型绑定到 HABTM 关联模型。

    【讨论】:

      【解决方案2】:

      当您将条件放入嵌套的 Contain 中时,您要求它仅检索具有该 ID 的类别。所以 - 它正在做你所要求的,但这不是你想要的。

      虽然看起来应该是可能的,但我唯一的运气就是做你想做的事(经过许多小时和几个 stackoverflow 问题)是通过加入而不是包含

      http://book.cakephp.org/view/1047/Joining-tables

      这不是完全相同的问题,但您可以查看我的一些代码,我在此处查询 HABTM 条件(我在底部回答了我的问题):Select All Events with Event->Schedule->Date between start and end dates in CakePHP

      【讨论】:

      • 我试图将Category 条件移动到主conditions 子句,但它失败了(因为它仍然没有JOIN 表,而是2 个SELECTs)。
      • @Ixa - 我不认为我建议这样做 - 除非您已将整个内容转换为加入。
      • 你没有,我只是在逻辑上扩展了你的评论当你把条件放在嵌套的 Contain 中时,你要求它只检索具有该 ID 的类别, - 因此,将该条件从嵌套的Contain 移动到主要的conditions 会将其应用于整个查询(实际上是这样,但它仍然不包括JOIN
      • 我的评论是为了指出当前代码的逻辑错误,但这并不是一个答案——我的答案是我指定我无法得到你在做什么的地方使用 Contain 工作 - 改为尝试 Joins。相信我,我也更愿意使用 Contain - 我尝试了 642 种不同的方法来让它发挥作用。不过,最后,我最终让它与 Joins 一起相当容易地工作。
      • 实际上我最终使用 Containable 使它工作 - 看我自己的答案
      猜你喜欢
      • 2015-01-04
      • 1970-01-01
      • 2012-07-06
      • 1970-01-01
      • 2012-09-23
      • 1970-01-01
      相关资源
      最近更新 更多