web-dev-qa-db-ja.com

Doctrine OneToManyのカスケードオプション

私はDoctrineマニュアルの 説明 カスケード操作の意味を理解するのに苦労しており、単純なManyToOne関係の観点からオプションを理解するのを手伝ってくれる人が必要です。

私のアプリケーションでは、Topicという名前のテーブル/エンティティの 'id'フィールドを参照する外部キーフィールドを持つArticleという名前のテーブル/エンティティがあります。

新しい記事を作成するとき、ドロップダウンメニューからトピックを選択します。これにより、Articleテーブルの「topic_id」外部キーフィールドに整数が挿入されます。

Articleエンティティに次のように$ topicの関連付けを設定しています:

/**
 * @ManyToOne(targetEntity="Topic")
 * @JoinColumn(name="topic_id", referencedColumnName="id", nullable=false)
 */
private $topic;

トピックエンティティには、Articleエンティティに関する往復アノテーションがありません。トピックは、どの記事がそれらを参照するかを気にしません。また、トピックを参照する記事が削除されても、トピックに何もする必要はありません。

Articleエンティティでカスケード操作を指定していないため、新しい記事を作成しようとすると、Doctrineはエラーをスローします。 "新しいエンティティは、カスケード永続化操作。新しいエンティティを明示的に永続化するか、リレーションシップでカスケード永続化操作を構成します。

したがって、Articleエンティティに含めるカスケード操作を選択する必要があることはわかっていますが、この状況でどの操作を選択するかをどのように知ることができますか?

Doctrineマニュアル、「切り離す」は正しいオプションのように聞こえます。しかし、他の人の同様の質問を研究する here および here 代わりに「persist」を使用します。

誰でも私が説明したような単純なManyToOneリレーションシップの観点で「持続」、「削除」、「マージ」、および「切り離し」の意味を理解するのに役立ちますか?

38
cantera

Doctrine2のドキュメント「 9.6。Transitive persistence/Cascade Operations 」では、$ articleを永続化するときに$ topicも永続化されるようにエンティティを設定する方法の例はほとんどありません。あなたの場合、私はトピックエンティティにこの注釈を提案します:

/**
 * @OneToMany(targetEntity="Article", mappedBy="topic", cascade={"persist", "remove"})
 */
 private $articles;  

このソリューションの欠点は、$ articlesコレクションをTopicエンティティに含める必要があることですが、ゲッター/セッターなしでプライベートのままにしておくことができます。

そして、@ kurt-krueckebergが言及したように、新しい記事を作成するときは、実際のトピックエンティティを渡す必要があります。

$topic = $em->getRepository('Entity\Topic')->find($id);
$article = new Article($topic);
$em->persist($article);
$em->flush();

// perhaps, in this case you don't even need to configure cascade operations

幸運を!

28

Doctrine Referenceのセクション6.10で説明されているような@OneToMany単方向の関連付けがある場合、フラッシュを呼び出す前にトピックを永続化するのを忘れた可能性があります。topic_id主キーを設定しないでください。記事内で、代わりにトピックインスタンスを設定します。

たとえば、次のようなArticleおよびTopicエンティティがあります。

<?php
namespace Entities;

/**
@Entity
@Table(name="articles")
*/
class Article {

/**
*  @Id
*  @Column(type="integer", name="article_id") 
*  @GeneratedValue
*/
    protected $id;  

/**
*  @Column(type="text") 
*/
 protected $text;

/** 
* @ManyToOne(targetEntity="Topic", inversedBy="articles")
* @JoinColumn(name="topic_id", referencedColumnName="topic_id")
*/ 
 protected $topic; 

 public function __construct($text=null)
 {
    if (!is_null($text)) {
         $this->text = $text;
    }
 }
 public function setArticle($text)
 {
     $this->text = $text;
 }

 public function setTopic(Topic $t)
{
     $this->topic = $t;
}
} 

<?php
namespace Entities;
/**
  @Entity
  @Table(name="topics")
*/
class Topic {

/**
*  @Id
*  @Column(type="integer", name="topic_id") 
*  @GeneratedValue
*/
    protected $id;  

    public function __construct() {}

    public function getId() {return $this->id;}
}

スキーマを生成した後:

# doctrine orm:schema-tool:create

これらのエンティティを永続化するコードは次のようになります

//configuration omitted..
$em = \Doctrine\ORM\EntityManager::create($connectionOptions, $config);

$topic = new Entities\Topic();
$article1 = new Entities\Article("article 1");
$article2 = new Entities\Article("article 2");
$article1->setTopic($topic);
$article2->setTopic($topic);
$em->persist($article1);
$em->persist($article2);
$em->persist($topic);

try {
    $em->flush();
} catch(Exception $e) {
    $msg= $e->getMessage();
    echo $msg . "<br />\n";
}
return;

これがお役に立てば幸いです。

0