9

我在 Doctrine 中遇到了单向多对多关系的问题。案例很简单:产品有很多标签。标签可以附加到产品,也可以附加到我模型中的任何“可标记”实体。这是我的代码片段:

/**
 * @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 tagsid))'”)。

当我更改 products_tags 表将 ON DELETE CASCADE 添加到外键时,它可以按我的意愿工作。我可以轻松删除 TAG ($em->remove($tag)) 和 PRODUCT ($em->remove($product),它们会自动从 products_tags 表中删除引用的行。

我的代码应该如何使用 ON CASCADE DELETE 外键获取 products_tags 表?我已经厌倦了 cascade={"all"} 但它失败了。

我知道,我可以从产品的标签集合中删除所有标签,但正如我所提到的,我想一步实现它,只需调用实体管理器对象的 remove 方法。

教义真的缺乏吗?

4

1 回答 1

25

好的,我通过挖掘 Doctrine2 文档来管理自己;)解决方案是将onDelete="cascade"添加到@JoinColumn

/**
 * @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 回答