我有两个基于 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();
我收到外键违规错误:
无法执行 UPDATE 语句 [UPDATE
image
SETFILE_UPLOAD_ID
=:p1,UPDATED_AT
=:p2 WHERE image.ID=:p3] [wrapped: SQLSTATE[23000]:完整性约束违规:1452 无法添加或更新子行:外键约束失败(DATABASENAME
.image
, 约束外image_FK_1
键 (file_upload_id
) 参考file_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 );
}
这种方法有效,但感觉很hacky。它也只能在这里使用,因为一旦保存了 $upload 对象,我就可以轻松地恢复外部引用 - 在其他情况下,它可能不那么简单。
是否有任何干净的方法可以防止从 $upload->save() 重新触发 $image->save() 的保存 - 而不会过多地干扰 Propel 的默认行为?谢谢。