Handling ForeignKeyConstraintViolationException #480
-
Hello, before I create issue, maybe I'm doing something wrong, so I ask here. I got 3 entities: Location: /**
* @property int $id {primary}
* @property Country $country {m:1 Country::$locations}
* @property string $name
* @property-read string $nameWithCountry {virtual}
*/
class Location extends Entity
{
protected function getterNameWithCountry(): string
{
return $this->name . ', ' . $this->country->name;
}
} Country: /**
* @property int $id {primary}
* @property string $name
* @property OneHasMany|array<Location> $locations {1:m Location::$country}
*/
class Country extends Entity
{
} Boat: * @property int $id {primary}
* @property Location $location {m:1 Location, oneSided=true}
* ...
*/
class Boat extends Entity
{
// rest
} When I remove Location, which is not related to any Boat, everything is fine. Removing logic is here: try {
$this->orm->location->removeAndFlush($location);
// $this->orm->removeAndFlush($location); <- did not helped
// $location->country->locations->remove($location); <- did not helped as well
} catch (InvalidStateException | ForeignKeyConstraintViolationException $e) {
$this->flashMessage(
'Location can not be removed, because is connected to some boat',
'danger',
);
} Exception is printed while rendering table: $location->country->name; But at this moment I would expect Location to be already removed. Any tips? Thank you very much! |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 7 replies
-
Orm needs to know what should happen if the location is removed and yet it is a location for boat:
I understand that oneSided had a reason to avoid potential performance issues when loading all relationships. Yet this should be solved by Nextras Orm 4.0 by introducing https://blog.nextras.org/orm-4-optimized-relationship/ |
Beta Was this translation helpful? Give feedback.
-
Hello and thank you for your reply, but that's not a problem (or it is?), cause I'm already catching Cascade is configured right here, I would expect |
Beta Was this translation helpful? Give feedback.
-
So If I understand you correctly, you expect that cathing the
|
Beta Was this translation helpful? Give feedback.
-
@hrach hello again, so I tried to rollback changes, first without But then, when I changed the value of the Here is how I modifed the removing logic: public function locationGridActionDelete(Location $location): void
{
try {
$this->orm->location->removeAndFlush($location);
} catch (InvalidStateException | ForeignKeyConstraintViolationException $e) {
$this->orm->location->getMapper()->rollback();
$this->orm->refreshAll(true);
$this->flashMessage(
'Lokaci nelze odstranit, jelikož je přiřazena nějaké lodi.',
'danger',
);
}
} So to be clear: |
Beta Was this translation helpful? Give feedback.
-
Ok, so the proper solution here is really to check the relationships upfront the entity removal /**
* @property int $id {primary}
* @property OneHasMany|Boats[] $boats {Boat::$location}
*/
class Location extends Entity {}
if ($this->location->boats->countStored() > 0) {
$this->flashMessage(
'Lokaci nelze odstranit, jelikož je přiřazena nějaké lodi.',
'danger',
);
return;
} Why it is recommended? Orm models data as entities and their consistency should be checked upfront. Other storage implementation (like non-relational database/storing simple serialized data) won't cover this data inconsistency. So it should be modeled in Orm. The alternative solution is to use DB checks (foreign key in this case). This needs to employ dbal and its transaction handling and let orm reinit afterwards (and it also requires this bug fixed, as aforementioned): try {
$this->orm->removeAndFlush($user);
} catch (ForeignKeyConstraintViolationException $e) {
/** @var DbalMapper $mapper */
$mapper = $this->orm->userStats->getMapper();
$mapper->rollback();
$this->orm->refreshAll();
} |
Beta Was this translation helpful? Give feedback.
Ok, so the proper solution here is really to check the relationships upfront the entity removal
Why it is recommended? Orm models data as entities and their consistency should be checked upfront. Other storage implementation (like non-relational database/storing simple serialized data) won't cover this data inconsistency. So it should be modeled in Orm.
The alternative solution is to use DB checks (for…