2

FileUpload と Image という 2 つの Propel ベース (Propel 1.6) モデル クラスがあります。

<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 をインスタンス化するとき、$upload を $image の下に登録してから、$image (2 番目) と $upload (1 番目) の両方のカスケード保存を期待して $image を保存してみてください ...

$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] [ラップ: 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 );
}

このアプローチは機能しますが、ハッキリと感じます。$upload オブジェクトが保存されると、外部参照を簡単に復元できるため、ここでのみ使用することもできます。それ以外の場合は、それほど単純ではない可能性があります。

$upload->save() からの $image->save() の保存の再トリガーを防止するクリーンな方法はありますか? Propel のデフォルトの動作にあまり干渉することはありませんか? ありがとう。

4

1 に答える 1

2

親オブジェクトで save を呼び出すだけで (FileUpload)、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

?>
于 2012-07-28T01:04:43.680 に答える