2

特定の(HABTMアソシエーション)Productに属するのリストをページ付けする必要があります。Category

私の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

(つまり、20Productsを選択してから、クエリを実行します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;

(つまり、= 3Productsに属する上位20を選択します)Categoryid

注: なしで考えられる解決策Containableは、(Daveが提案したように)結合を使用することです。 この投稿は、$this->paginate['joins']HABTMアソシエーションをページ付けするために構築するための非常に便利なヘルパーを提供します。

Containable注:偽のhasOneバインディングよりも、より洗練されたソリューションを探しています。

4

2 に答える 2

6

ついに私は自分がやりたいことをする方法を見つけたので、それを答えとして投稿します:

強制するJOIN(そして関連付けられたモデルの条件を介してフィルタリングできるようにする)には、偽の関連付けを使用する必要がContainableありますhasOne

私の場合、コードは次のように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-の2番目の引数として、bindModelバインディングを永続的にすることに注意してください。これが必要なのは、の前にpaginate()問題が発生すると、一時的なバインディングがリセットされるためです。したがって、後で手動で行うことをお勧めします。find('count')find('all')unbindModel

また、条件にHABTM関連モデルの複数のIDが含まれている場合は、 (Aziz'group' => 'Product.id'が回答に示したように)に追加して、重複するエントリを削除することをお勧めします(MySQLでのみ機能します)。$this->paginate[]

更新: ただし、このアプローチには、結合アプローチ(Davecategory_idが提案)と比較して1つの重大な欠点があります。条件は中間モデルの外部キー(私の場合)にのみ適用できます。関連モデルの他のフィールドで条件を使用する場合は、おそらく別bindModel('hasOne')のバインディング中間モデルをHABTM関連モデルに追加する必要があります。

于 2011-07-10T18:11:20.840 に答える
1

ネストされたContainに条件を設定すると、そのIDを持つカテゴリのみを取得するように要求されます。だから-それはあなたが求めていることをしているが、それはあなたが望んでいることではない。

それは可能であるように思われますが、あなたがやろうとしていることを私がやった唯一の運は(何時間もスタックオーバーフローの質問の後)、ContainではなくJoinsを経由することです

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

これはまったく同じ問題ではありませんが、HABTM条件に対してクエリを実行するコードの一部を確認できます(下部にある質問に回答しました)。[イベント]->[スケジュール]->[開始日と終了日の間の日付]ですべてのイベントを選択します。 CakePHP

于 2011-07-10T05:20:52.467 に答える