2

我有两个基于 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 imageSET FILE_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 的默认行为?谢谢。

4

1 回答 1

2

您可以只在父对象(FileUpload)上调用保存,Propel 在将子对象添加到父对象后保存子对象并在父对象上调用保存。

<?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

?>
于 2012-07-28T01:04:43.680 回答