CakePHP多重嵌套联接
我有一个应用程序,其中几个模型通过hasMany/belongsTo关联进行链接。例如,A有许多B,B有许多C,C有许多D,D有许多E。同样,E属于D,D属于C,C属于B,B属于A。使用可包含行为对于控制每次查询返回的信息量非常有用,但在使用涉及表D的条件时,试图从表a获取数据时,我似乎遇到了问题。例如,下面是我的“a”模型的一个示例:CakePHP多重嵌套联接,cakephp,database-agnostic,Cakephp,Database Agnostic,我有一个应用程序,其中几个模型通过hasMany/belongsTo关联进行链接。例如,A有许多B,B有许多C,C有许多D,D有许多E。同样,E属于D,D属于C,C属于B,B属于A。使用可包含行为对于控制每次查询返回的信息量非常有用,但在使用涉及表D的条件时,试图从表a获取数据时,我似乎遇到了问题。例如,下面是我的“a”模型的一个示例: class A extends AppModel { var $name = 'A'; var $hasMany = array(
class A extends AppModel {
var $name = 'A';
var $hasMany = array(
'B' => array('dependent' => true)
);
function findDependentOnE($condition) {
return $this->find('all', array(
'contain' => array(
'B' => array(
'C' => array(
'D' => array(
'E' => array(
'conditions' => array(
'E.myfield' => $some_value
)
)
)
)
)
)
));
}
}
这仍然会返回“A”中的所有记录,如果相关的“E”记录不满足条件,则我只得到以下结果:
Array(
[0] => array(
[A] => array(
[field1] => // stuff
[field2] => // more stuff
// ...etc
),
[B] => array(
[field1] => // stuff
[field2] => // more stuff
// ...etc
),
[C] => array(
[field1] => // stuff
[field2] => // more stuff
// ...etc
),
[D] => array(
[field1] => // stuff
[field2] => // more stuff
// ...etc
),
[E] => array(
// empty if 'E.myfield' != $some_value'
)
),
[1] => array( // ...etc )
)
如果“E.myfield”!=$有些值,我根本不希望返回记录
我希望这足够清楚地表达我的问题
基本上,我想要以下查询,但以一种与数据库无关的/CakePHP-y方式:
SELECT *
FROM A INNER JOIN
(B INNER JOIN
(C INNER JOIN
(D INNER JOIN
E ON D.id=E.d_id)
ON C.id=D.c_id)
ON B.id=C.b_id)
ON A.id=B.a_id
WHERE E.myfield = $some_value
您的问题是对Containable行为以及
Model::find
中的contain
选项的误解。第一个代码示例中的Model::find
调用将大致转换为:
找到所有的答案;然后找到与每个A关联的所有B;然后找到与每个B关联的所有C;然后找到与每个C关联的所有D;最后,查找与每个D关联的所有E,其中E中的一个字段与指定值匹配
condition语句只过滤D的结果,而不是从上到C,再到B,再到A的链。如果您扫描SQL日志,您将看到大量的查询从包含链的每一级拉出
为了让CakePHP直接从数据库返回您想要的结果,您必须在a和E之间配置一个hasOne
关联。使用您描述的长链,这可能相当麻烦。它看起来像(读:未测试):
另一种方法是从Model::find
调用中完全删除E.my_值
条件,并在末尾执行相当复杂的Set::extract
:
$results = $this->find('all', array(
'contain' => array(
'B' => array(
'C' => array(
'D' => array(
'E' => array()
)
)
)
)
));
return Set::extract("/A/B/C/D/E[my_field={$some_value}]/../../../../", $results);
但是,对于深度Set::extract
来说,性能将是一个真正的问题,特别是当您在很多行上操作时
编辑:我只想强调一下,如果这个操作需要扩展,那么Set::extract
选项是多么糟糕的想法。它将整个过滤负担从数据库引擎转移到PHP的数组函数上。是的,我可能不会为Set::extract选项操心……而且我对这样设置hasOne关系有点谨慎,因为a有许多B,等等,我仍然不需要保持这种关系正常工作。谢谢你的帮助,我想我必须咬紧牙关,用“手”过滤记录……不管它值多少钱,如果你绑定额外的hasOne协会,hasMany协会应该可以继续工作,没有问题。实际上,Model::bindModel的默认行为是创建一个“一次性”绑定;关联将在下一个Model::find()操作后重置。
$results = $this->find('all', array(
'contain' => array(
'B' => array(
'C' => array(
'D' => array(
'E' => array()
)
)
)
)
));
return Set::extract("/A/B/C/D/E[my_field={$some_value}]/../../../../", $results);