1

我有一个表product,这些表中的项目在诸如cart_itemorder_item以及shipping_item等表中被引用。

所有这些引用都是可选的(product_id 在这些表中设置为可为空)。

我需要有一种方法来删除产品并仍然保留其他表的记录。我能想到的一种方法是进入所有这些表,将 product_id 设置为 null,然后返回 product 表进行删除。但是,由于我可能不知道引用产品的所有表(许多其他捆绑包可能具有引用此产品的实体),有没有办法让我知道所有这些关联以循环并设置为 null?

(或者也许有更好的方法?)

PS:这是一个购物车的想法,所有者可能希望删除过期产品进行清理,但对于订购的、已发货的物品,他们仍然需要保留记录。

编辑1:

这是 OrderItem 实体中产品引用的定义:

/**
 * @var \Product
 *
 * @ORM\ManyToOne(targetEntity="Product")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="product_id", referencedColumnName="id")
 * })
 */
private $product;

我得到的错误:

PDOException:SQLSTATE [23000]:完整性约束违规:1451 无法删除或更新父行:外键约束失败(test. order_item, C ONSTRAINT fk_order_item_product1FOREIGN KEY ( product_id) REFERENCES product( id) ON DELETE NO ACTION ON UPDATE NO ACTION)

编辑2:

我最初将 onupdate="SET NULL" 设置为 order_item 实体,并认为这就足够了,但不是:

/**
 * @var \Product
 *
 * @ORM\ManyToOne(targetEntity="Product")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="product_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
 * })
 */
private $product;

之后,我还必须更新数据库模式。

4

1 回答 1

3

假设您在拥有实体product和其他实体之间建立了适当的关系,例如cart_item应该有一个外键,您想要的行为是原则 2 的默认行为。

看看这里的手册

作为一个例子,他们展示了删除一个User实体及其对应的Comments

$user = $em->find('User', $deleteUserId);

foreach ($user->getAuthoredComments() AS $comment) {
    $em->remove($comment);
}
$em->remove($user);
$em->flush();

该示例指出:

如果没有对所有已编写的评论进行循环,Doctrine 将使用 UPDATE 语句仅将外键设置为 NULL,并且在 flush() 操作期间仅将用户从数据库中删除。

这向我表明,在您的情况下,您实际上想要这种行为。因此,只需删除product实体,学说 2 将自动找到所有其他具有属于该产品的外键的实体并将其设置为NULL

编辑
您的错误消息表明,在尝试删除product实体后,仍然存在 foreign_keys,即 Doctrine 没有将它们正确设置为 null。您需要确保添加cascade属性,特别是添加remove到您的实体关系中。它看起来像下面这样:

<?php
class Product
{
    //...
    /**
     * Bidirectional - One-To-Many (INVERSE SIDE)
     *
     * @OneToMany(targetEntity="Cart", mappedBy="product", cascade={"remove"})
     */
    private $carts;
    //...
}
于 2013-03-27T09:16:45.430 回答