Мне нужна помощь в понимании того, как cascade
работает с ассоциациями сущностей Symfony2, в частности с опцией «удалить». Потому что, когда я пытаюсь удалить объект, существует конфликт внешнего ключа базы данных и он не будет удаляться из базы данных.
У меня есть два объекта тестирования:
/** * @ORM\Entity * @ORM\Table(name="test") */ class Test extends Entity\Base { /** * This is a OneToOne Unidirectional association, just so that we can get the * current published version easily, based on the publishedId. * @ORM\OneToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\TestVersion") * @ORM\JoinColumn(name="publishedId", referencedColumnName="id") */ protected $published; /** * @ORM\Column(type="integer", nullable=true) */ protected $publishedId = NULL; /** * This is the regular OneToMany Bi-Directional Association, for all the versions. * @ORM\OneToMany(targetEntity="\Gutensite\CmsBundle\Entity\View\TestVersion", mappedBy="view", cascade={"persist", "remove"}, orphanRemoval=true) */ protected $versions; } /** * @ORM\Entity * @ORM\Table(name="test_version") */ class TestVersion extends Entity\Base { /** * @ORM\ManyToOne(targetEntity="\Gutensite\CmsBundle\Entity\View\Test", inversedBy="versions") * @ORM\JoinColumn(name="viewId", referencedColumnName="id") */ protected $view; /** * The primary view entity that this version belongs to. * @ORM\Column(type="integer", nullable=true) */ protected $viewId; }
* Примечание. Первоначально у меня было двунаправленное отношение OneToOne, у которого был каскад = {"persist", "remove"}, но понял, что это не нужно. В любом случае, проблема в точности такая же.
В контроллере я создаю тестовый объект следующим образом:
$view = new Test(); $version = new TestVersion(); // associate the version with the view $view->addVersion($version); // mark this version as the published version (this is where the problem happens, though) $view->setPublished($version); $em->persist($view); $em->flush();
И это создает одну основную запись для теста и одну связанную версию в test_version:
|---------------------| | table: test | |---------------------| | id | publishedId | | 100 | 500 | |---------------------| |---------------------| | table: test_version | |---------------------| | id | viewId | | 500 | 100 | |---------------------|
* Примечание. Test_version.viewId устанавливается в ручной строке с помощью моего метода test.addVersion (), который вызывает $ version-> setView ($ this).
Но когда я иду, чтобы удалить основной объект в тесте:
$view = $em->getRepository("GutensiteCmsBundle:View\Test")->find($request->query->get('id')); $em->remove($view); $em->flush();
Он пытается удалить основной тестовый объект, но не работает, потому что на него ссылается test_version.viewId.
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`cms`.`test_version`, CONSTRAINT `FK_635D070BCEB972AA` FOREIGN KEY (`viewId`) REFERENCES `test` (`id`))
И если я вручную попытаюсь удалить запись test_version в базе данных, она также завершится с аналогичной ошибкой:
ERROR 1451: 1451: Cannot delete or update a parent row: a foreign key constraint fails (`cms`.`test`, CONSTRAINT `FK_D87F7E0C628CCE00` FOREIGN KEY (`publishedId`) REFERENCES `test_version` (`id`)) SQL Statement: DELETE FROM `cms`.`test_version` WHERE `id`='17'
Soooooo ….. в чем смысл cascade = {"remove"}, если он фактически не удаляет связанный объект (или материнский объект, если на то пошло)?
Единственный способ, которым я могу удалить эти записи, – это если я отключу $ view-> publishId, который нарушает совпадение внешней связи.
$view = $em->getRepository("GutensiteCmsBundle:View\Test")->find($request->query->get('id')); $view->setPublishedId(NULL); $em->persist($view); $em->flush(); $em->remove($view); $em->flush();
По-видимому, это вызвано из-за совпадения между ассоциациями OneToOne и OneToMany. Я могу жить с этой необходимостью, чтобы отключить опубликованный файл перед удалением представления. Но мне хотелось бы получить отзывы от эксперта, чтобы узнать, кажется ли это проблематичным. Или предложение о лучшем решении для этих ассоциаций. Тем не менее, у меня есть другие записи (например, несколько маршрутов), которые указывают на единый объект представления, поэтому версии выходят из их собственной сущности (также для того, чтобы сохранить большую часть данных в другой таблице для оптимизации). Таким образом, моя модель кажется вполне логичной, например, я хочу быстро найти ссылку на опубликованную версию. И я думал, что однонаправленные отношения не вызовут проблем. Но это так …