我的主机对象有许多与之关联的选项对象。在编辑表单中,用户可以(de)选择选项并保存新的关联集。这是使用发布数据上的saveAll()实现的。结果是
但是没有发生的是
问题:也可以saveAll()这样做,数据结构如何实现这种效果呢?
相关信息:
我处理编辑表单的代码实际上更复杂(因此我在这里没有引用它)但它导致了书中描述的数据结构:
( [Host] => ( ... host object fields ... ),
[Option] => ( [0] => ( ... first option object fields ... ),
...
[n] => ( ... nth option object fields ... )
)
)
现在,如果原始主机具有未包含在0..n数组中的关联选项,则saveAll()将不会检测到此选项,也不会删除该关联对象。
不确定这是否相关,但我使用的是CakePHP 1.3。
答案 0 :(得分:2)
不是一个优雅的解决方案,但对我有用。
if ($this->Main->saveAll($this->data))
{
$this->Main->query(sprintf(
'DELETE '
. 'FROM extraneous '
. 'WHERE main_id = \'%s\' AND modified < (SELECT modified FROM main WHERE id = \'%1$s\')'
, mysql_real_escape_string($this->Main->id)
));
}
请注意,您的表格需要有modified字段。
答案 1 :(得分:2)
如果手动将所有内容都包装到事务中,您可以确保以原子方式执行所有操作。
可以使用数据源的begin()
,rollback()
和commit()
方法完成此操作:
$this->Main->begin();
if ( !$this->Main->save(...) ) {
$this->Main->rollback();
return false;
}
// Perform saves in related models...
if ( !$this->Main->MainRelatedModel->save(...) ) {
$this->Main->rollback();
return false;
}
// Perform deletes in extraneous records...
if ( !$this->Main->MainRelatedModel->delete(...) ) {
$this->Main->rollback();
return false;
}
// Everything went well, commit and close the transaction
$this->Main->commit();
这里的主要缺点是交易无法嵌套,因此您无法使用saveAll()
。您必须逐步保存/删除所有内容,而不是一次性保存。
答案 2 :(得分:1)
saveAll()
不会删除数据库中的任何内容。
我想最好的方法是在保存之前删除与当前主机相关的选项,然后添加它们。但是,如果你需要更新那些已经存在的(你呢?)因为某些原因(比如:选项与其他一些模型有关),我想你可以尝试编写一段代码,删除未选择的选项。 / p>
答案 3 :(得分:1)
寻找这个,我注意到还没有内置的CakePHP解决方案。为此,我将以下代码添加到我的模型中:
private $oldBarIds = array();
public function beforeSave($options = array() {
parent::beforeSave($options);
$this->oldBarIds = array();
if ($this->id && $this->exists() && isset($this->data['Bar'])) {
$oldBars = $this->Bar->find('all', array(
'fields' => array('id'),
'conditions' => array(
'Bar.foo_id' => $this->id
)
));
$this->oldBarIds = Hash::extract($oldBars, '{n}.id');
}
}
检查保存数据中是否存在Bar
。如果是,它将获得当前id的当前id,将它们设置为$this->oldBarIds
。然后当保存成功时,它应该删除旧的:
public function afterSave($created, $options = array()) {
parent::afterSave($created, $options);
if (!$created && $this->oldBarIds) {
$this->Bar->deleteAll(array(
'Bar' => $this->oldBarIds
));
}
}
这种删除方式由模型处理,只有在保存成功时才会发生。应该能够将此添加到某个行为中,可能有一天会这样做。
答案 4 :(得分:0)
HABTM
删除所有相关记录,然后重新创建所需内容。正如PawelMysior建议的那样,您可以通过在保存之前手动删除关联的记录来使用hasMany
来实现此目的。然而,危险在于,保存失败,你失去了以前的状态。
我会使用GJ解决方案的变体并在成功保存后删除它们,而是循环遍历冗余ID数组并使用Cake的Model-&gt; del()方法。这样就可以保留所有内置的错误处理。