【问题标题】:Integrity constraint violation, foreign key constraint fails违反完整性约束,外键约束失败
【发布时间】:2014-11-09 02:05:45
【问题描述】:

我有 3 个实体:Invoice、InvoiceItemService、Asset。

首先,我创建一个 Invoice 和一个 InvoiceItemService,并将它们与 InvoiceItemService 端的 ManyToOne 关系链接在一起(因此 InvoiceItemService 是所有者端)。

然后,我可以从 Invoice 对象创建一个资产。资产是发票的副本,总计为负数。当我创建资产时,我也将 Invoice 的 InvoiceItemService 链接到资产,在 InvoiceItemService 和资产之间具有多对一关系。

当我删除一个 Invoice 时,一切正常,Invoice、Asset 和 InvoiceItemService 使用 cascade={"remove"} 选项删除。

当我删除资产时,我只想删除资产。但是我得到了这个外键错误。

这是我的实体:

class Invoice
{
    /**
     * @ORM\OneToMany(targetEntity="Evo\BackendBundle\Entity\Asset", mappedBy="invoice", cascade={"remove"})
     */
    protected $assets;

    /**
     * @ORM\OneToMany(targetEntity="Evo\BackendBundle\Entity\InvoiceItemService", mappedBy="invoice", cascade={"persist", "remove"})
     */
    protected $services;
}

class Asset
{
    /**
     * @ORM\ManyToOne(targetEntity="Evo\BackendBundle\Entity\Invoice", inversedBy="assets")
     * @ORM\JoinColumn(nullable=false)
     * @Exclude
     */
    protected $invoice;

    /**
     * @ORM\OneToMany(targetEntity="Evo\BackendBundle\Entity\InvoiceItemService", mappedBy="asset")
     */
    protected $services;
}

class InvoiceItemService extends InvoiceItem
{
    /**
     * @ORM\ManyToOne(targetEntity="Evo\BackendBundle\Entity\Invoice", inversedBy="services")
     * @ORM\JoinColumn(nullable=false, onDelete="CASCADE")
     * @Type("Evo\BackendBundle\Entity\Invoice")
     * @Exclude
     */
    protected $invoice;

    /**
     * @ORM\ManyToOne(targetEntity="Evo\BackendBundle\Entity\Asset", inversedBy="services")
     * @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
     * @Type("Evo\BackendBundle\Entity\Asset")
     * @Exclude
     */
    protected $asset;
}

【问题讨论】:

  • 是否有其他实体可能依赖 Asset 作为外键?您的错误可能与您在此处发布的这三者之间的关系完全无关。
  • 我很确定问题出在这里,根据 SQL 错误:a foreign key constraint fails (`evotest`.`sf_invoices_items_services`, CONSTRAINT `FK_38F5C7765DA1941` FOREIGN KEY (`asset_id`) REFERENCES `sf_assets` (`id`)) 实际上,当资产被删除时,我需要一个原则选项来将 InvoiceItemService 中的asset_id 设置为 NULL .在 InvoiceItemService#asset 属性中尝试了@ORM\JoinColumn(nullable=true, onDelete="SET NULL"),但错误仍然存​​在
  • 删除所有引用资产的 InvoiceItemService 项目由您决定。 D2 删除级联不够聪明,无法返回上游删除。

标签: symfony doctrine-orm foreign-keys constraints entity-relationship


【解决方案1】:

正如上面 cmets 中提到的 Cerad,您需要自己实现此行为。

由于您需要访问实体管理器,因此您无法通过资产实体本身的简单生命周期回调来执行此操作。相反,您需要注册一个服务来监听事件并在此时执行操作。

示例实现

app/config.yml

services:
    your.bundle.association.manager:
        class: Your\Bundle\Model\AssociationManager
        tags:
            - { name: doctrine.event_listener, event: preRemove }

然后,服务类本身(未经测试 - 可能有错误)

namespace Your\Bundle\Model;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\EntityManager;
use Your\Bundle\Entity\Asset;

class AssociationManager
{
  public function preRemove(LifecycleEventArgs $args)
  {
    if ($entity instanceof Asset)
    {
      $this->removeAssetAssociations($asset, $args->getEntityManager());
      return;
    }
  }

  protected function removeAssetAssociations(Asset $asset, EntityManager $em)
  {
    foreach ($asset->getServices() as $invoiceItemService)
    {
      $invoiceItemService->asset = null;
      $em->persist($invoiceItemService);
    }
  }
}

希望这会有所帮助。

【讨论】:

  • 不错不错。关键是要了解我必须手动取消这些关系。我已经在资产移除上设置了一个事件监听器,所以它是小菜一碟。实际上,我只使用了您的 foreach() 部分,其他所有内容都已编码。日复一日,我发现教义越来越神奇,但我想我在这里发现了它的一个局限,似乎教义不能自动处理关系分离。无论如何,谢谢你的回复。也感谢 Cerad。为你们俩 +1。
猜你喜欢
  • 2016-04-24
  • 2018-03-20
  • 2021-06-10
  • 2021-03-24
  • 1970-01-01
  • 2020-01-14
  • 2020-12-28
  • 1970-01-01
相关资源
最近更新 更多