CakePHP:在“查找”条件下使用第二级深度模型关联,返回重复的结果

时间:2012-02-08 19:50:13

标签: cakephp model associations cakephp-2.0

我已经阅读了很多帖子,花了几个小时在cakephp.org上查看文档,甚至尝试了各种实际例子,我似乎无法做到这一点。我所拥有的是3个表格如下:

  • 项目
  • project_tags
  • 标记

当有人添加新项目时,他们会选择标签,这些标签是从标签表中的预定义列表中选择的。然后,他们输入的标签将使用project_id和tag_id字段存储在project_tags中。

模型关系如下:

  • Project hasMany projectTag
  • projectTag belongsTo Project
  • ProjectTag belongsTo Tag

我是否有正确的关系对我来说仍然是微不足道的,但我在这里尝试了很多可能性。

我要做的是对特定标签的所有项目执行查找。我通过以下方式完成了这项工作:

$this->Project->contain(array('ProjectTag' => 'Tag', 'User' => array('id')));
$projects = $this->Project->find('all', array('conditions' => array('ProjectTag.tag_id' => '6')));

结果是一个SQL错误,即ProjectTag.tag_id列不存在。这告诉我关联中有错误,但在哪里?

这是因为我在使用可包含的时候不能在我喜欢的条件下使用二级深度关联的hasMany模型吗?如果是这样,我该如何纠正?

我知道很久很抱歉。任何人都可以对这种奇怪的情况有所了解吗?

我尝试的另一种方法是在Project上使用unbindModel(),删除所有与ProjectTag的绑定,然后使用bindModel()和条件ProjectTag.project_id = Project.id添加一个hasOne,但这导致4条记录返回相同的项目,每个ProjectTag一个,这似乎不对。

我正在使用可包含的行为,并在AppModel中设置了recursive =。

非常感谢任何帮助。 感谢

2 个答案:

答案 0 :(得分:2)

你遇到的问题是你在模特的关系中错了。 理想情况下,您的案例是关系hasAndBelongsToMany。

Project hasAndBelongsToMany Tag Tag hasAndBelongsToMany Proyect

在这种情况下,这是自然关系。 projectTag表只是一个中间表,不是cakephp中的模型。

了解更多信息:http://book.cakephp.org/1.3/view/1044/hasAndBelongsToMany-HABTM

答案 1 :(得分:1)

对于所有可能偶然发现这篇文章的人来说,尝试在查找或分页查询中包含2级以上深度关联的模型并不是一项简单的任务。

持续提升的第一点是CakePHP为每个hasMany和hasAndBelongsToMany关联执行单独的查询,因此几乎无法将它们包含在查找条件中。

我收到了2x解决方案:

1)构建自定义查询类型

2)使用unbindModel和bindModel函数并重新创建关联为hasOne

我选择了第2点,因为当我阅读文档时,第1点似乎有问题(并且仅作为最后的手段被推荐)并且它允许我动态地更改关联,然后重置它,继续愉快地与关联按照我的意图。

对于那些感兴趣的人,我有一个模型项目,其中包含属于Tag的许多ProjectTag。在我的查找类型中无法使用Tag或ProjectTag,因此我执行了以下操作:

我在Project,ProjectTag和Tag上使用了unbindModel()方法,删除了所有关联,基本上取消了所有关系的链接。

然后我将bindModel()应用于Project,ProjectTag和Tag。最重要的是我应用这些绑定的顺序(层次结构),因为我使用了'condition'属性,它允许我使用SQL WHERE条件将模型'A'链接到模型'B'。例如:

$this->Project->ProjectTag->unbindModel(array(
'belongsTo' => array('Tag')
));

$this->Project->unbindModel(array('hasMany' => array('ProjectTag')));

$this->Project->bindModel(array('hasOne' => array('ProjectTag' => array('foreignKey' => false, 'conditions' => array('ProjectTag.project_id = Project.id')))));

$this->Project->bindModel(array('hasOne' => array('Tag' => array('foreignKey' => false, 'conditions' => array('Tag.id = ProjectTag.tag_id')))));

我们现在可以使用Tag.id,就好像它与Project有一个hasOne关系,基本上允许我们在返回相关项目时直接在Tag上应用查找条件。

您必须取消绑定所讨论模型使用的所有关系,否则它将会中断。

我希望这可以帮助那些偶然遇到同样问题的人。