I have a Symfony3 project using Doctrine 2.6 to manage the database.
I get an Integrity constraint violation
error when I call the remove
method the EntityManager
in a certain order.
I've always considered this method (as well as persist
) to work no matter in which order entities are passed to them, I was wrong.
The database runs on MySQL and has the following structure:
The goal is to remove a Menu
entity. I've simplified the case so the Menu
is only linked to one Offer
, and one Component
.
The offer is linked to the same Component
as the menu.
So it looks like this:
- Menu [#12 Menu Of the Day]
| - Component [#23 Dessert]
| | - Product [#14 Pineapple]
| - Offer [#42 Dessert only]
| | - Component [#23 Dessert]
| | | - Product [#14 Pineapple]
Now this is the code that crashes :
$em = $this->doctrine->getManager();
$menu = $em->getRepository(Menu::class)->findOneBy(['ref' => 'V0dQ']);
// Remove menu components (ex: starter, dish, dessert, etc.)
$menuComponents = $menu->getComponents();
$menuComponent = $menuComponents[0];
$menu->removeComponent($menuComponent);
// Remove components products
$componentsProducts = $menuComponent->getComponentProducts();
$componentProduct = $componentsProducts[0];
$menuComponent->removeComponentProduct($componentProduct);
// Remove offers (ex: start + dish, dish + dessert, etc.)
$offers = $menu->getOffers();
$offer = $offers[0];
$menu->removeOffer($offer);
// Same as menu components
$offerComponents = $offer->getComponents();
$offerComponent = $offerComponents[0];
$offer->removeComponent($offerComponent);
// Everything MUST be persisted/removed in one place.
$em->remove($componentProduct);
$em->remove($menuComponent);
$em->remove($offer);
$em->remove($offerComponent);
$em->remove($menu);
$em->flush();
I works by putting the call to remove($menuComponent)
after the call to remove($offer)
, like so:
$em->remove($componentProduct);
$em->remove($offer);
$em->remove($menuComponent);
$em->remove($offerComponent);
$em->remove($menu);
This is a raw example of the problem. In reality I have a pretty complex "Api engine" (like Api Platform) in which everything is handled in a generic way.
I need a clear understanding of what happens to abstract a solution to any case in the future, that's where I call for your help.
Do you see a simple rule to determine which entity must be passed to remove()
first?