如何使用bindModel和custom finder将CakePHP 2模型关联更改为深度链接?
我正在尝试复制此SQL查询结果,该结果有效:如何使用bindModel和custom finder将CakePHP 2模型关联更改为深度链接?,php,mysql,cakephp,associations,cakephp-2.x,Php,Mysql,Cakephp,Associations,Cakephp 2.x,我正在尝试复制此SQL查询结果,该结果有效: SELECT r.id, r.day, s.ddbroute_id, s.delivery_id, d.id, d.laststatusid, t.id, t.delivery_id, t.statusstage_id, st.id, st.stage FROM ddbroutes r LEFT JOIN ddbrouteslots s on r.id = s.ddbroute_id LEFT JOIN deliveries d on s.deliv
SELECT r.id, r.day, s.ddbroute_id, s.delivery_id, d.id, d.laststatusid, t.id, t.delivery_id, t.statusstage_id, st.id, st.stage
FROM ddbroutes r
LEFT JOIN ddbrouteslots s on r.id = s.ddbroute_id
LEFT JOIN deliveries d on s.delivery_id = d.id
LEFT JOIN trackingstatuses t on d.laststatusid = t.id
LEFT JOIN statusstages st on t.statusstage_id = st.id
我使用的是CakePHP2模型
我有五个表(包括以下字段): 模型中设置了以下关系:
Ddbroute hasMany Ddbrouteslot (Ddbrouteslot belongsTo Ddbroute)
Delivery hasOne Ddbrouteslot (Ddbrouteslot belongsTo Delivery)
Delivery hasMany Trackingstatus (Trackingstatus belongsTo Delivery)
Statusstage hasMany Trackingstatus (Trackingstatus belongsTo Statusstage)
虽然交付有一个Ddbrouteslot(这将是HASMONY-修订版-现在保留为hasOne),但对于任何单个Ddbroute,每个Ddbrouteslot只关联一个交付。在所有模型中都设置了Containable。我不知道是否需要先使用unbindModel(它没有更改错误消息)
我在Ddbroute.php模型文件中的代码(仅限于交货表)
在另一个控制器中,要运行查找操作:
$this->LoadModel('Ddbroute');
$ddbstatuses = $this->Ddbroute->find('ddbstatuses');
$this->set(compact('ddbstatuses')); // to make available in a view
我还进一步尝试使用长连接数组,但该查询没有带来任何传递、跟踪状态或状态阶段信息,尽管该查询似乎已经运行
public $findMethods = array('ddbstatuses' => true);
protected function _findDdbstatuses($state, $query, $results = array()) {
if ($state === 'before') {
ClassRegistry::init('Delivery'); // not sure these three lines were needed so I tried with and without them
ClassRegistry::init('Trackingstatus');
ClassRegistry::init('Statusstage');
$query['joins'] = array(
array(
'table' => 'ddbrouteslots',
'alias' => 'Ddbrouteslot',
'type' => 'LEFT',
'conditions' => array(
'Ddbroute.id = Ddbrouteslot.ddbroute_id'
)),
array(
'table' => 'deliveries',
'alias' => 'Delivery',
'type' => 'LEFT',
'conditions' => array(
'Ddbrouteslot.id = Delivery.id'
)),
array(
'table' => 'trackingstatuses',
'alias' => 'Trackingstatus',
'type' => 'LEFT',
'conditions' => array(
'Delivery.laststatusid = Trackingstatus.id'
)),
array(
'table' => 'statusstages',
'alias' => 'Statusstage',
'type' => 'LEFT',
'conditions' => array(
'Trackingstatus.statusstage_id = Statusstage.id'
))
);
$query['contain'] = array(
'Ddbrouteslot',
'Delivery', // Not sure I should be adding these other models, so I tried with and without them
'Trackingstatus',
'Statusstage'
);
return $query;
}
return $results;
}
经过一些帮助,我现在有四个解决方案来获取我的数据,尽管实际上其中三个是第一个的变体。我相对缺乏经验,有些基本的东西我不欣赏 1。在控制器中
$this->LoadModel("Ddbrouteslot");
$res = $this->Ddbrouteslot->find("all", array(
"conditions" => array(
"Ddbrouteslot.delivery_id > 0",
"Ddbrouteslot.ddbroute_id" => 45
),
"contain" => array(
"Ddbroute",
"Delivery" => array(
"Trackingstatus" => array(
"order" => array(
"Trackingstatus.id" => "desc"
),
"limit" => 1,
"Statusstage"
)
)
)
);
来自DebugKit的计时:主查询为20ms;Trackingstatus和Statusstage是针对四个相关交付的额外查询,每个查询18ms x 4;总时间为164ms。这是相当缓慢,这是不理想的
这是从第二个模型Ddbrouteslot开始的,因为它与Ddbroute和Delivery都有直接关系。任何关联都没有变化。
从Ddbrouteslot到交货的belongsTo关系运作良好。
在交付和交付id跟踪状态之间已经存在很多关系
2。使用SQL
$this->LoadModel("Ddbroute");
$qres = $this->Ddbroute->query(
"SELECT *
FROM
ddbroutes AS r
LEFT JOIN ddbrouteslots s on r.id = s.ddbroute_id
LEFT JOIN deliveries d on s.delivery_id = d.id
LEFT JOIN trackingstatuses t on d.laststatusid = t.id
LEFT JOIN statusstages st on t.statusstage_id = st.id
WHERE s.delivery_id > 0 AND s.ddbroute_id = 45
;"
debug($qres);
$rres = $this->Ddbroute->find("all", array(
"conditions" => array(
"Ddbroute.id" => 45
),
"recursive" => -1,
"contain" => array(
"Ddbrouteslot" => array(
"conditions" => array(
"Ddbrouteslot.delivery_id > 0"
),
"Delivery" => array(
"Trackingstatus" => array(
"order" => array(
"Trackingstatus.id" => "desc"
),
"limit" => 1,
"Statusstage"
)
)
)
)
));
debug($rres);
计时:耗时19毫秒。这意味着速度要快得多。Cake文档中不建议这样做,而且很明显,它在数据库之间的可移植性不如纯Cake查找
3。更改基本型号
$this->LoadModel("Ddbroute");
$qres = $this->Ddbroute->query(
"SELECT *
FROM
ddbroutes AS r
LEFT JOIN ddbrouteslots s on r.id = s.ddbroute_id
LEFT JOIN deliveries d on s.delivery_id = d.id
LEFT JOIN trackingstatuses t on d.laststatusid = t.id
LEFT JOIN statusstages st on t.statusstage_id = st.id
WHERE s.delivery_id > 0 AND s.ddbroute_id = 45
;"
debug($qres);
$rres = $this->Ddbroute->find("all", array(
"conditions" => array(
"Ddbroute.id" => 45
),
"recursive" => -1,
"contain" => array(
"Ddbrouteslot" => array(
"conditions" => array(
"Ddbrouteslot.delivery_id > 0"
),
"Delivery" => array(
"Trackingstatus" => array(
"order" => array(
"Trackingstatus.id" => "desc"
),
"limit" => 1,
"Statusstage"
)
)
)
)
));
debug($rres);
计时:主查询为18ms;对于四次相关交付,交付、跟踪状态和状态阶段各为18ms x 4;总时间为234ms。速度较慢,因为每次发货都需要进行交付,因为它不在Ddbroute的模型内。
改变递归并没有什么不同
4。使用自定义查找 这是与上面1.)相同的查询,但只是使用了一个自定义的find方法
public $findMethods = array('ddbstatuses' => true);
protected function _findDdbstatuses($state, $query, $results = array()) {
if ($state === 'before') {
$query['conditions'] = array(
"Ddbrouteslot.delivery_id > 0",
"Ddbrouteslot.ddbroute_id" => 45
);
$query['contain'] = array(
"Ddbroute",
"Delivery"=> array(
"Trackingstatus" => array(
"order" => array(
"Trackingstatus.id" => "desc"
),
"limit" => 1,
"Statusstage"
)
)
);
return $query;
}
return $results;
}
我现在有了一个解决方案,但是使用CakePHP模型进行查询要比下面的SQL解决方案(2)慢得多。字段“Delivery.laststatusid”可以链接到“Trackingstatus.id”,那么就不需要“order”约束。我用一个unbindModel和bindModel尝试了这一点,试图将hasOne和belongsTo关联起来。由于主键Delivery.id未被使用,我的语法包括
'foreignKey'=>false,'conditions'=>array('
Delivery
laststatusid`=Trackingstatus
id
')`)。我收到一条错误消息,laststatusid是未知列。关于如何更快一些有什么想法吗?