CakePHP 多重嵌套连接
我有一个应用程序,其中多个模型通过 hasMany/belongsTo 关联进行链接。例如,A hasMany B,B hasMany C,C hasMany D,D hasMany E。此外,E 属于 D,D 属于 C,C 属于 B,B 属于 A。使用 Containable 行为非常适合控制每个查询返回的信息量,但在使用涉及表 D 的条件时尝试从表 A 获取数据时,我似乎遇到了问题。例如,这是我的“A”的示例模型:
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 )
)
When If 'E.myfield' != $some_value, I don根本不想返回记录。
我希望这能够足够清楚地表达我的问题...
基本上,我想要以下查询,但是以与数据库无关/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
I have an App in which several of the models are linked by hasMany/belongsTo associations. So for instance, A hasMany B, B hasMany C, C hasMany D, and D hasMany E. Also, E belongs to D, D belongs to C, C belongs to B, and B belongs to A. Using the Containable behavior has been great for controlling the amount of information comes back with each query, but I seem to be having a problem when trying to get data from table A while using a condition that involves table D. For instance, here is an example of my 'A' model:
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
)
)
)
)
)
)
));
}
}
This still gives me back all the records in 'A', and if it's related 'E' records don't satisfy the condition, then I just get this:
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 )
)
When If 'E.myfield' != $some_value, I don't want the record returned at all.
I hope this expresses my problem clearly enough...
Basically, I want the following query, but in a database-agnostic/CakePHP-y kind of way:
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的问题是对 Containable 行为的作用以及
Model::find
中contain
选项的作用的误解。第一个代码示例中的Model::find
调用将大致转换为:条件语句仅过滤 D 的结果,而不是沿着链向上过滤到 C、B、A。如果您扫描 SQL 日志,您将看到大量查询提取
contain链。
为了让 CakePHP 直接从数据库返回您想要的结果,您必须在 A 和 E 之间配置一个
hasOne
关联。对于您所描述的长链,这可能相当笨重。它看起来像(阅读:未经测试):另一种方法是从
Model::find
调用中完全删除E.my_value
条件,而是执行相当的复杂的Set::extract
最后:对于深度
Set::extract
来说,性能将是一个真正的问题,特别是当您对很多行进行操作时。编辑:我只是想强调如果此操作需要扩展,
Set::extract
选项是多么糟糕的想法。它将整个过滤负担从数据库引擎转移到 PHP 的数组函数上。Your issue is a misconception of what the Containable behaviour does and what the
contain
option does inModel::find
. TheModel::find
call in your first code-sample would translate roughly to:The condition statement only filters results of D, not up the chain to C, then B, then A. If you scan the SQL log, you'll see an enormous number of queries pulling out each level of your
contain
chain.In order to get CakePHP to return the results as you desire, straight from the database, you'd have to configure a
hasOne
association between A and E. With a long chain such as you describe, this might be fairly unwieldy. It'd look something like (read: untested):An alternative is to remove the
E.my_value
condition entirely from theModel::find
call, and instead perform a fairly complexSet::extract
at the end:Performance would be a real issue with a deep
Set::extract
though, especially if you were operating on a lot of rows.EDIT: I just want to emphasise how terrible an idea the
Set::extract
option is if this operation needs to scale. It shifts the entire filtering burden from the database engine onto PHP's array functions.