我有两种情况,即进行两次类似的查询,在一种情况下,相关模型的虚拟字段的代码不会生成到sql查询语句中,因此找不到。
在数据库中:
*两个主表(hospitals
和hotels
)
*一个引用的表contacts
*主表具有指向联系表的各种字段。对医院,例如一个director_contact_id
和一个janitor_contact_id
。对于酒店director_contact_id
和concierge_contact_id
。
在CakePHP中
* Hospital
模型有两个belongsTo关系DirectorContact
和JanitorContact
* Hotel
模型有两个belongsTo关系DirectorContact
和ConciergeContact
*联系人有一个虚拟字段full_name
,类似于CONCAT(…)
在HospitalController中,每当我需要一个绑定到医院数据的联系人数据时,我就可以这样做:
$contain = array();
…
$contain['DirectorContact'] = array('fields' => array('id','full_name'));
…
$this->Hospital->find('all', array(
…
'contain' => $contain,
…
));
生成的sql代码包含
CONCAT(…) AS DirectorContact__full_name
然而,在HotelController中同样不起作用。我也在那里:
$contain['DirectorContact'] = array('fields' => array('id','full_name'));
如果我
debug($this->Hotel->DirectorContact->virtualFields);
我得到了
array(
'full_name' => 'CONCAT(…)'
)
但是当我运行动作时,我得到一个SQL错误,说明字段full_name
未知。我可以看到,在生成的sql查询中缺少CONCAT(…) AS DirectorContact__full_name
。
在这两种情况下,联系表都被多次引用,至少有一个具有不同别名的关联。所以我不确定为什么CakePHP在一个案例中生成正确的查询而在另一个案例中没有。
当然,find语句比我在这里说的更复杂,包含更多,包含连接和字段。
问题1 :有谁知道什么可能触发CakePHP丢弃生成关联模型虚拟字段的代码?
我读到可容纳的行为有点微妙,在某些情况下最好使用连接。
因此,在虚拟字段不起作用的一种情况下,我使用了连接而不是包含。然而,虚拟字段没有生成,所以我明确地为两个字段做了这个:
$fields[] = 'DirectorContact.id';
$fields[] = 'CONCAT(…) AS `DirectorContact__name_or_company`';
$fields[] = 'ConciergeContact.id';
$fields[] = 'CONCAT(…) AS `ConciergeContact__name_or_company`';
如果我调试查询结果:
array(
'Hotel' => array(
'id' => '123',
),
'DirectorContact' => array(
'id' => '456',
'name_or_company' => 'Some name'
),
(int) 0 => array(
'ConciergeContact__name_or_company' => 'Some other name',
),
'ConciergeContact' => array(
'id' => '789'
),
)
因此,对于第一个关联,自动化工作和CakePHP将虚拟字段DirectorContact__name_or_company
的内容写入关联数组的DirectorContact
部分,但另一个被放入“常规”部分键0引用的计算字段。
但更有趣的是:如果我将字段定义中模型引用的顺序交换为
$fields[] = 'ConciergeContact.id';
$fields[] = 'CONCAT(…) AS `ConciergeContact__name_or_company`';
$fields[] = 'DirectorContact.id';
$fields[] = 'CONCAT(…) AS `DirectorContact__name_or_company`';
结果是
array(
'Hotel' => array(
'id' => '123',
),
'ConciergeContact' => array(
'id' => '789'
),
(int) 0 => array(
'ConciergeContact__name_or_company' => 'Some other name',
'DirectorContact__name_or_company' => 'Some name',
),
'DirectorContact' => array(
'id' => '456',
),
)
所以现在自动化不再起作用了,两个虚拟领域都被纳入了一般部分。
问题2 :有没有人知道这个的原因,以及如何让CakePHP的自动化适用于所有情况?
(使用版本2.4.3)
答案 0 :(得分:1)
在深入研究CakePHP的代码之后,我找到了原因。
如果为查询定义fields选项,则不会创建virtualFields(即使您将它们添加到fields选项中)。
在单位DboSource.php中有函数read(Model $model, $queryData = array(), $recursive = null)
。
该功能代码的片段:
if (!empty($queryData['fields'])) {
$bypass = true;
…
} else {
…
}
$_associations = $model->associations();
…
foreach ($_associations as $type) {
foreach ($model->{$type} as $assoc => $assocData) {
…
if ($model->useDbConfig === $linkModel->useDbConfig) {
if ($bypass) {
$assocData['fields'] = false;
}
if ($this->generateAssociationQuery($model, $linkModel, $type, $assoc, $assocData, $queryData, $external, $null) === true) {
…
}
}
}
}
因此,当定义fields选项时,变量$bypass
将设置为true。进一步向下,在构建所有关联模型的查询代码的情况下,当$bypass
为真时,关联模型的字段定义设置为false。这显然也会删除虚拟字段。
然后,当您在查询的字段选项中包含该字段时,将无法找到它。
相当合乎逻辑......