0

У меня есть 3 объекта: счет-фактура, InvoiceItemService, Asset.Нарушение ограничения целостности, ограничение внешнего ключа не работает

Сначала я создаю счет-фактуру и службу InvoiceItemService, и я связываю их вместе с отношением ManyToOne на стороне InvoiceItemService (поэтому InvoiceItemService является стороной владельца).

Затем я могу создать объект из объекта «Счет-фактура». Актив - это копия счета-фактуры с отрицательным итогом. Когда я создаю Asset, я связываю InvoiceItemService счета с активом тоже с отношением ManyToOne между InvoiceItemService и 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; 
} 
+0

Существуют ли другие объекты, которые могут полагаться на «Asset» для внешнего ключа? Ваша ошибка может быть полностью не связана с отношениями между этими тремя, которые вы разместили здесь. –

+0

Я уверен, что проблема здесь, в соответствии с ошибкой SQL: '' 'ограничение внешнего ключа не работает (' evotest'.'sf_invoices_items_services', CONSTRAINT 'FK_38F5C7765DA1941' FOREIGN KEY (' asset_id') ССЫЛКИ 'sf_assets' ('id'))' '' На самом деле, мне понадобится опция doctrine для установки 'asset_id' в NULL в InvoiceItemService, когда объект будет удален. попробовал '@ORM \ JoinColumn (nullable = true, onDelete =" SET NULL ")' в свойстве свойства InvoiceItemService #, но ошибка все еще существует – VaN

+1

Вам решать удалить любые объекты InvoiceItemService, ссылающиеся на актив. Каскад удаления D2 недостаточно умен, чтобы вернуться назад и удалить. – Cerad

ответ

1

Как Cerad упоминалось в предыдущих комментариях, вы должны реализовать такое поведение самостоятельно.

Поскольку вам нужен доступ к диспетчеру сущности, вы не можете сделать это с помощью простого обратного вызова жизненного цикла для объекта Asset. Вместо этого вам нужно будет зарегистрировать службу для прослушивания события и выполнить действие в этот момент.

Примера реализация

приложение/config.yml

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

И потом, сам класс обслуживания (unstested - может иметь ошибки)

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); 
    } 
    } 
} 

Надеется, что это помогает.

+0

хорошо. Ключ должен был понять, что я должен был отключить эти отношения вручную. У меня уже был прослушиватель событий, настроенный на удаление Asset, поэтому это был кусок пирога. Фактически, я использую только часть 'foreach()', все остальное уже закодировано. день за днем ​​я нахожу доктрину все более и более удивительной, но я думаю, что нашел здесь одно из своих ограничений, кажется, что Доктрина не может автоматически обрабатывать отношения. В любом случае, спасибо за ваш ответ. Благодаря Cerad тоже. +1 для вас обоих. – VaN

Смежные вопросы