Doctrine multiple OneToMany/ManyToOne contrainte d'intégrité bidirectionnelle violation

dans la Doctrine la plus récente sur Symfony2 en essayant de travailler sur la relation bidirectionnelle multiple entre deux objets.

personne objet propriétaire a une adresse postale et puis plusieurs adresses secondaires dans une collection, et je supprime () la personne, je veux que toutes ses adresses soient également supprimés (mais supprimer une adresse ne devrait pas supprimer une personne), mais je reçois cette erreur -

An exception occurred while executing 'DELETE FROM address WHERE id = ?' with
params {"1":"fb5e47de-2651-4069-b85e-8dbcbe8a6c4a"}:

[PDOException] SQLSTATE[23000]: Integrity constraint violation: 1451
Cannot delete or update a parent row: a foreign key constraint fails
(`db`.`address`, CONSTRAINT `FK_633704 C29C1004E`
FOREIGN KEY (`person_id`) REFERENCES `person` (`id`))

class Person
{

    /**
     * @var Address postalAddress
     *
     * @ORMOneToOne(targetEntity="Address", cascade={"all"}, orphanRemoval=true)
     * @ORMJoinColumn(onDelete="cascade")
     */
    private $postalAddress;

    /**
     * @var DoctrineCommonCollectionsCollection otherAddresses
     *
     * @ORMOneToMany(targetEntity="Address", mappedBy="person", cascade={"all"}, orphanRemoval=true)
     */
    private $otherAddresses;


}

class Address
{

    /**
     * @var Person person
     *
     * @ORMManyToOne(targetEntity="Person", inversedBy="postalAddress, otherAddresses")
     * @ORMJoinColumn(nullable=false)
     */
    private $person;
}

j'ai pensé que cela pourrait parce que le

inversedBy="postalAddress, otherAddresses"

Je ne pense pas que multiple inversedBy soit supporté; alors j'ai aussi essayé de changer

@ORMJoinColumn(nullable=false)

pour accepter les valeurs null, mais j'ai toujours l'erreur.

il ne s'agit évidemment pas d'un exemple banal de personne/Adresse mais quelque chose de plus complexe, mais c'était ma meilleure tentative d'abstraction.

je suis sûr que j'ai manqué quelque chose d'évident. Quelqu'un peut-il aider?

7
demandé sur Gottlieb Notschnabel 2013-04-24 19:41:14

1 réponses

Cassé Relationnel Définition

alors que ce que vous faites peut avoir du sens d'un point de vue purement logique, il ne le fait pas d'un point de vue des données relationnelles, et en particulier n'a aucun sens du point de vue de la Doctrine.

Doctrine est d'essayer de maintenir les 3 types de relations:

  • Adresse (propriétaire) [bi-directional] $personne --Many:One--> $otherAddresses Personne
  • Adresse (propriétaire) [bi-directional] $personne --Many:One--> $ postalAddress Personne
  • Personne (propriétaire) [uni-directionnelle] $postalAddress --One:One--> $ id Adresse

Vous voyez le problème?

utilisez des normes relationnelles pour résoudre ce problème.

la solution simple ici est d'utiliser le modèle de conception très commun de une primaire pour une collection. Essentiellement, vous n'avez besoin que d'une seule relation:

  • Adresse (propriétaire) [bi-directional] $personne --Many:One--> $ autresadresses Personne

puis, Ajouter à l'adresse une propriété qui définit cette adresse comme étant la primaire. Programattically gérer cela dans la Personne et l'Adresse des entités:

Class Person
{
    . . .
    public function getPrimaryAddress() {
        if (null === $this->primaryAddress) {
            foreach($this->getOtherAddresses() as $address) {
                if ($address->isPrimary()) {
                    $this->primaryAddress = $address;
                    break;
                }
            }
        }

        return $this->primaryAddress;
    }

    // similar for the setter, update the old address as not primary if there is one, set the new one as primary.
}

utilisez deux relations différentes, mais ne traversez pas le flux

si vous gardez la relation unipersonnelle unidirectionnelle de personne à personne, le problème se résout lui-même.

  • Adresse (propriétaire) [bi-directional] $personne --Many:One--> $ autresadresses Personne
  • Personne (propriétaire) [uni-directionnelle] $postalAddress --One:One-->Adresse

vous allez quand même avoir des problèmes ici, parce que La Doctrine se plaindra si: - la principale ( PostalAddress) adresse de ne pas avoir les deux côtés de l' Plusieurs: Un défini. (ainsi votre adresse "principale" devra aussi être dans le $otherAddresses collecte). - tenter de supprimer ou de cascade des suppressions et des mises à jour résultera en ces deux relations conflictuelles, "croisant les flux" des contraintes relationnelles de la doctrine, de sorte que vous aurez à gérer programmatically ces opérations.

2
répondu Tony Chiboucas 2017-10-17 15:14:37