我有两个基于 Propel (Propel 1.6) 的模型类:FileUpload 和 Image:
<table name="file_upload">
<column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />
<column name="name" type="varchar" size="500" required="false" />
<column name="mime_type" type="varchar" size="100" required="true" />
<column name="data" type="blob" required="false" lazyLoad="true" />
</table>
<table name="image">
<column name="id" type="integer" required="true" primaryKey="true" autoIncrement="true" />
<column name="file_upload_id" type="integer" required="true" />
<foreign-key foreignTable="file_upload" onDelete="restrict">
<reference local="file_upload_id" foreign="id" />
</foreign-key>
</table>
当我实例化一个新的图像$image、新的FileUpload$upload时,在$image下注册$upload,然后尝试保存$image,希望能够级联保存$image(第二个)和$upload(第一个)...
$image = new Image();
$upload = new FileUpload();
// [set required properties in both models]
$image->setFileUpload( $image );
$image->save();
我收到外键违规错误:
Unable to execute UPDATE statement [UPDATE
image
SETFILE_UPLOAD_ID
=:p1,UPDATED_AT
=:p2 WHERE image.ID=:p3] [wrapped: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (DATABASENAME
.image
, CONSTRAINTimage_FK_1
FOREIGN KEY (file_upload_id
) REFERENCESfile_upload
(id
))]
我发现该错误是由于 $upload->save() 调用 BaseFileUpload->doSave() 引起的,其中,它会重新触发 $image->save():
if ($this->collImages !== null) {
foreach ($this->collImages as $referrerFK) {
if (!$referrerFK->isDeleted()) {
$affectedRows += $referrerFK->save($con);
}
}
}
...这意味着 FileUpload 会镜像其他对象对它的反向引用,即使它本身仅被引用,而不引用其他任何东西。
当我重写 Image->save() 以首先清除链接 FileUpload 上的所有镜像引用,然后调用 Parent::save() 时,问题消失了:
public function save( PropelPDO $con = null )
{
$upload = $this->getFileUpload();
if ( null !== $upload && $upload->isModified() ) {
$upload->clearAllReferences();
$upload->save( $con );
$this->setFileUpload( $upload );
}
return parent::save( $con );
}
这种方法有效,但感觉很hack。它也只能在这里使用,因为一旦保存 $upload 对象,我就可以轻松恢复外部引用 - 在其他情况下,它可能不会那么简单。
是否有任何干净的方法可以防止从 $upload->save() 重新触发 $image->save() 的保存 - 而又不会过多干扰 Propel 的默认行为?谢谢。
最佳答案
您只需在父对象 (FileUpload) 上调用 save,Propel 会在将子对象添加到父对象并在父对象上调用 save 后保存子对象。
<?php
$upload = new FileUpload();
$image = new Image();
$image2 = new Image();
// set required fields on $upload, $image, and $image2
// ....
$upload->addImage($image);
$upload->addImage($image2);
$upload->save(); // save upload and new images
?>
关于php - 推进 ORM : originating save() re-triggered in cascaded save,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11694195/