我有一个应用程序,其中几个模型由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 )
)
当如果'E.myfield'!= $ some_value,我根本不希望记录返回。
我希望这能够清楚地表达我的问题......
基本上,我想要以下查询,但是以数据库无关/ 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
答案 0 :(得分:2)
您的问题是对可包含行为的作用以及contain
选项在Model::find
中的作用的误解。您的第一个代码示例中的Model::find
调用将大致转换为:
找到所有A;然后找到与每个A相关的所有B;然后找到与每个B相关的所有C;然后找到与每个C相关的所有D;最后,找到与每个D关联的所有E,其中E中的一个字段与指定值匹配。
条件语句只过滤D的结果,而不过滤链到C,然后是B,然后是A.如果你扫描SQL日志,你会看到大量的查询从你的{{1链。
为了让CakePHP直接从数据库中返回结果,你必须在A和E之间配置一个contain
关联。如你所描述的那样,这可能是相当笨拙。它看起来像(读:未经测试):
hasOne
另一种方法是完全从$this->bindModel(array('hasOne'=>array(
'B'=>array(
'foreignKey' => false,
'conditions' => array('A.id = B.a_id')
),
'C'=>array(
'foreignKey' => false,
'conditions' => array('B.id = C.b_id')
),
'D'=>array(
'foreignKey' => false,
'conditions' => array('C.id = D.c_id')
),
'E'=>array(
'foreignKey' => false,
'conditions' => array('D.id = E.d_id')
)
)));
$this->find('all', array(
'conditions' => array( 'E.my_field' => $some_value )
));
调用中移除E.my_value
条件,而最后执行相当复杂的Model::find
:
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
选项如果这个操作需要扩展有多糟糕。它将整个过滤负担从数据库引擎转移到PHP的数组函数。