php - 推进 ORM : originating save() re-triggered in cascaded save

标签 php propel

我有两个基于 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 SET FILE_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, CONSTRAINT image_FK_1 FOREIGN KEY (file_upload_id) REFERENCES 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 );
}

这种方法有效,但感觉很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/

相关文章:

php - 使用正则表达式从 <a> HTML 标记获取所有属性

php - Symfony 1.4 插入 : Accessing Table Data via Foreign Key

php - symfony2 的 sfguard 包

mysql - 推进对象集合将列别名绑定(bind)到外部表对象,而不是将其取出

php - Propel:从别名连接表中选择列

php - 无法将 FOR UPDATE 附加到标准推进

php - Mysql非顺序插入问题

php - 对内爆值调用函数?

javascript - 如何在 PHP 中处理 JSON 模型?

php - 超薄自动加载器和命名空间问题