9

Doctrine の一方向の ManyToMany 関係に問題があります。ケースは非常に簡単です。製品には多くのタグがあります。タグは、製品だけでなく、モデル内の「タグ付け可能な」エンティティにも添付できます。ここに私のコードのスニペットがあります:

/**
 * @Entity 
 * @Table(name="products")
 **/
class Product {

    /** some other fields here */

    /**
     * @ManyToMany(targetEntity="Tag")
     * @JoinTable(name="products_tags",
     *      joinColumns={@JoinColumn(name="product_id", referencedColumnName="id")},
     *      inverseJoinColumns={@JoinColumn(name="tag_id", referencedColumnName="id")}     
     *      )
     */
    protected $tags;

}

Tag クラスの一方向の関係コードが省略されているため。

このように定義された関連付けに対して、Doctrine は次の SQL コードを生成しました (製品テーブルとタグテーブルの SQL はスキップされます):

CREATE TABLE `products_tags` (
  `product_id` int(11) NOT NULL,
  `tag_id` int(11) NOT NULL,
  PRIMARY KEY (`product_id`,`tag_id`),
  KEY `IDX_E3AB5A2C4584665A` (`product_id`),
  KEY `IDX_E3AB5A2CBAD26311` (`tag_id`),
  CONSTRAINT `FK_E3AB5A2CBAD26311` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`),
  CONSTRAINT `FK_E3AB5A2C4584665A` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |

タグが付いている商品を削除したいのですが。

/* $product is already persisted, $em is an Entity Manager */
$em->remove($product);
$em->flush();

整合性制約違反が原因で失敗することは明らかです (「親行を削除または更新できません: 外部キー制約が失敗します ( products_tags, CONSTRAINT FK_E3AB5A2CBAD26311FOREIGN KEY ( tag_id) REFERENCES tags( id))」)。

ON DELETE CASCADE を外部キーに追加して products_tags テーブルを変更すると、必要に応じて機能します。TAG ($em->remove($tag)) と PRODUCT ($em->remove($product) を簡単に削除できます。これにより、products_tags テーブルから参照された行が自動的に削除されます。

ON CASCADE DELETE 外部キーを使用して products_tags テーブルを取得するコードはどのようになりますか? 私はすでに cascade={"all"} に飽きましたが、失敗しました。

製品のタグ コレクションからすべてのタグを削除できることはわかっていますが、前述したように、エンティティ マネージャー オブジェクトの remove メソッドを呼び出すだけで、1 つのステップでそれを実現したいと考えています。

Doctrine には本当にそれが欠けているのでしょうか?

4

1 に答える 1

25

わかりました、私はDoctrine2のドキュメントを掘り下げて自分自身を管理しました;)解決策は@JoinColumnにonDelete="cascade"を追加することです。

/**
 * @Entity 
 * @Table(name="products")
 **/
class Product {

    /** some other fileds here */

    /**
     * @ManyToMany(targetEntity="Tag")
     * @JoinTable(name="products_tags",
     *      joinColumns={@JoinColumn(name="product_id", referencedColumnName="id", onDelete="cascade")},
     *      inverseJoinColumns={@JoinColumn(name="tag_id", referencedColumnName="id", onDelete="cascade")}     
     *      )
     */
    protected $tags;

}

cascade={"all"} は (アプリ内の) オブジェクト レベルで管理され、onDelete="cascade" はデータベース レベルで管理されることに注意してください。

于 2013-09-28T17:25:07.287 に答える