如何在CakePHP中的第三个n..n(hasAndBelongsToMany)关系中联接两个表?

时间:2020-03-06 14:31:10  来源:igfitidea点击:

我有两个表," makes"和" models"的" n ... n"结构。到目前为止没有问题。

在第三个表格("产品")中,例如:

id
make_id
model_id
...

我的问题是在我的ProductsController内为一个特定make的产品创建一个视图,其中只包含make模型:

我认为这可以工作:

var $uses = array('Make', 'Model');

$this->Make->id = 5; // My Make

$this->Make->find(); // Returns only the make I want with it's Models (HABTM)
$this->Model->find('list'); // Returns ALL models
$this->Make->Model->find('list'); // Returns ALL models

因此,如果我想使用list传递到视图中以创建单选按钮,则必须在make数组中执行一次foreach()来查找所有模型标题并创建一个新数组并将其发送到通过$ this-> set()查看。

$makeArray = $this->Make->find();
foreach ($makeArray['Model'] as $model) {
    $modelList[] = $model['title'];
}
$this->set('models', $models)

有没有更简单的方法来获得该列表而无需强调make数组。在我的应用程序中开发此类方案将是一项常见的任务。

预先感谢任何提示!

解决方案

这是我的提示:在尝试使用Cake库进行重构之前,请尝试以常规SQL编写查询。本质上,我们正在做数据库可以为我们完成的许多额外工作。
方法(仅用于显示不好的SQL):

SELECT * FROM makes, models, products WHERE make_id = 5

我们无需考虑这些关系(除非Cake自动魔术地理解表的关系)

我们可能正在寻找将这些东西结合在一起的东西:

SELECT models.title FROM models 
INNER JOIN products 
  ON products.model_id = models.model_id 
  AND products.make_id = 5

希望这是朝正确方向前进的推动力?

我们所有不同的Make-> find()和Model-> find()调用都是完全独立的。即使Make-> Model-> find()与Model-> find()相同,Cake也不会记住或者考虑我们在其他模型中已经发现的内容。我们正在寻找的东西是这样的:

$this->Product->find('all', array('conditions' => array('make_id' => 5)));

检出Set :: extract()方法,从$ this-> Make-> find()的结果中获取模型标题的列表

从评论中判断,我们要查询的是如何从某个模型中获得结果,而该条件位于与HABTM相关的模型中。 IE。通常在原始SQL中使用JOIN语句执行的操作。
目前,这是Cake的少数弱点之一。有不同的策略可以解决这个问题。

  • 让相关的模型B返回模型A的所有可能候选者的ID,然后对模型A进行第二次查询。
$this->ModelB->find('first', array('conditions' => array('field' => $condition)));
array(
    ['ModelB'] => array( ... ),
    ['ModelA'] => array(
        [0] => array(
            'id' => 1
        )
)

现在,我们拥有一个符合我们条件的,属于ModelB的所有ModelA的ID数组,我们可以使用Set :: extract()轻松提取它们。基本上等价于" SELECT model_a.id FROM model_b JOIN model_a WHERE model_b.field = xxx"。接下来,我们寻找ModelA:

$this->ModelA->find('all', array('conditions' => array('id' => $model_a_ids)));

这将产生" SELECT model_a。* FROM model_a WHERE id IN(1、2、3)",这是执行JOIN语句的一种round回方式。如果我们需要多个以上相关模型的条件,请重复执行直到获得ModelA的所有ID,SQL将使用所有ID的交集(ID IN(1、2、3)和ID IN(3、4、5) ))。

  • 如果我们只需要ModelB上的一个条件,但想要检索ModelA,则只需搜索ModelB。 Cake将自动为我们检索相关的ModelA(请参见上文)。我们可能需要再次Set :: extract(),但这可能已经足够了。
  • 我们可以使用上述方法,并将其与Containable行为结合使用,以更好地控制结果。
  • 如果所有其他方法均失败,或者上述方法仅产生过多的开销,我们仍然可以使用$ this-> Model-> query()编写自己的原始SQL。如果我们遵循Cake SQL标准(使用FROM model_as AS ModelA正确命名表),Cake仍将正确地对结果进行后处理。

希望这能给我们正确的方向。

解决方案可以通过在模型的habtm数组中使用" with"操作来实现。

使用with,我们可以定义"中间"表,如下所示:

$habtm = " ...
  'with' => 'MakeModel',
   ... ";

在内部,我们可以在Model或者Controller中向条件find发出条件。

参见:http://www.cricava.com/blogs/index.php?blog=6&title=modelizing_habtm_join_tables_in_cakephp_&more=1&c=1&tb=1&pb=1