IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Doctrine2 PHP Discussion :

Référence circulaire entre entités : Integrity constraint violation 1451


Sujet :

Doctrine2 PHP

  1. #1
    Membre habitué Avatar de Soobook
    Homme Profil pro
    Développeur Web
    Inscrit en
    Août 2005
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Réunion

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2005
    Messages : 98
    Points : 149
    Points
    149
    Par défaut Référence circulaire entre entités : Integrity constraint violation 1451
    Bonjour à tous.

    Peut-être, avant tout, que ma manière de modéliser les choses n'est pas la bonne. Dans ce cas, je vous remercie d'avance de me "recadrer"...

    J'ai quatre entités : User, Application, Bundle et Entity (U, A, B et E), et les relations suivantes (remove et persist en cascade) :

    U 1-n A
    A 1-n B
    B 1-n E

    Jusque là pas de problème. Sauf que mon User peut/doit avoir deux de ses Entity par défaut.
    J'ai donc créé sur User les champs entity1 et entity2, puis les relations 1-1 correspondantes.

    L'intérêt est de pouvoir accéder directement aux Entity par défaut de l'User, chose indispensable dans mon appli.

    Sauf que la suppression d'un A ou d'un B provoque désormais une erreur Integrity constraint violation: 1451 que je n'arrive pas à corriger.

    J'ai essayé différentes choses, dont les deux solutions proposées ici, sans succès.

    Si je supprime les relations entre User et Entity ça fonctionne à nouveau. J'envisage donc différentes solutions pour contourner le problème :
    - remplacer les champs entity1 et entity2 de User par des simples integers et gérer à la main la relation.
    - gérer les statuts default1 et default2 au niveau de Entity via des champs booléens et gérer à la main la relation.
    - laisser tel quel et gérer la suppression à la main dans mes controllers.
    - jeter mon ordi par la fenêtre et me reconvertir en boucher-charcutier .

    Mais aucune de ces solutions n'est satisfaisante, elles complexifient quelque chose qui peut/doit être simple. Si vous pouvez m'aider, j'en serai très reconnaissant.
    Merci d'avance,

    Soobook.

    Erreur complète :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    An exception occurred while executing 'DELETE FROM bundle WHERE id = ?' with params {"1":13}:
     
    SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`misc`.`entity`, CONSTRAINT `FK_E284468F1FAD9D3` FOREIGN KEY (`bundle_id`) REFERENCES `bundle` (`id`))
    Définition des relations :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    # User :
        /**
         * @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Application", mappedBy="user", cascade={"remove"})
         * @ORM\OrderBy({"name" = "ASC"})
         */
        protected $applications;
     
        /**
         * @ORM\OneToOne(targetEntity="\sfCommands\ContentBundle\Entity\Entity")
         * @ORM\JoinColumn(name="entity1_id", referencedColumnName="id")
         */
        private $entity1;
     
        /**
         * @ORM\OneToOne(targetEntity="\sfCommands\ContentBundle\Entity\Entity")
         * @ORM\JoinColumn(name="entity2_id", referencedColumnName="id")
         */
        private $entity2;
     
    #Application :
        /**
         * @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Bundle", mappedBy="application", cascade={"remove"})
         * @ORM\OrderBy({"name" = "ASC"})
         */
        protected $bundles;
     
        /**
         * @ORM\ManyToOne(targetEntity="\sfCommands\UserBundle\Entity\User", inversedBy="applications", cascade={"persist"})
         * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
         */
        protected $user;
     
    #Bundle :
        /**
         * @ORM\ManyToOne(targetEntity="\sfCommands\ContentBundle\Entity\Application", inversedBy="bundles", cascade={"persist"})
         * @ORM\JoinColumn(name="application_id", referencedColumnName="id")
         */
        protected $application;
     
        /**
         * @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Entity", mappedBy="bundle", cascade={"remove"})
         * @ORM\OrderBy({"name" = "ASC"})
         */
        protected $entitys;
     
    #Entity :
        /**
         * @ORM\ManyToOne(targetEntity="\sfCommands\ContentBundle\Entity\Bundle", inversedBy="entitys", cascade={"persist"})
         * @ORM\JoinColumn(name="bundle_id", referencedColumnName="id")
         */
        protected $bundle;
    Javascript est la pornstar des langages de programmation : souple, puissant, tu lui fais faire ce que tu veux, et ça peut finir bien crade.
    ---
    https://www.bgaze.fr

  2. #2
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    725
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juin 2011
    Messages : 725
    Points : 1 050
    Points
    1 050
    Par défaut
    Bonjour,

    Si tu as configuré un cascade delete entre Bundle et Entity ainsi qu'avec Application et Bundle, à priori ton application fonctionne, les Entités liés sont supprimés en même temps que l'on supprime une Application ou un Bundle.
    Si tu veux que chaque User soit liés forcément à deux Entité, ton programme fonctionne également et empéche que la base de donnés soit mise à jour avec des données invalides.

    Il est préférable que ton programme plante à ce moment que lorsque que tu feras un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $user->getEntity1()->doSomething();//Fatal Error si entity1 est vide!
    Si dans ton application les deux relations de User vers Entity sont obligatoires, que doit-il se passer lorsque l'on supprime une Entity qui est lié ?

    Soit lorsque l'on supprime une Entité, on met à jour les champs entity1 et entity2 précédemment occupé par cette entité en la remplaçant par une Entité par défaut.
    ou bien on considère que ces relations User->entity sont optionnelles
    ou bien une Entité n'a pas forcément de Bundle associés.
    ...

    Le problème ne tient pas vraiment à Doctrine ou SQL, mais à la logique de ton application.

  3. #3
    Membre habitué Avatar de Soobook
    Homme Profil pro
    Développeur Web
    Inscrit en
    Août 2005
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Réunion

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2005
    Messages : 98
    Points : 149
    Points
    149
    Par défaut
    Bonjour,

    arnooo999, merci de ta réponse, mais je ne pense pas que ce soit ça. C'était mal précisé dans mon premier post, mais ces relations User -> Entity sont en effet optionnelles.
    A confirmer, mais il me semble que ce soit toujours le cas avec les relation entre entités de Doctrine. Je viens de tester et les "jointures" (@ORM\OneToOne, @ORM\ManyToOne, ...) n'admettent pas d'argument nullable.

    De toute façon rien n'interdit au niveau de mon modèle que les entités par défaut d'un user soient à null : elles le sont lorsqu'il est créé. Rien ne l'oblige d'ailleurs à créer tout de suite des entités.

    Au niveau de mon application, l'existence d'une entité A, B ou E est toujours contrôlée car on peut très bien avoir créé une A, par exemple, mais pas encore de B (donc pas de E) à l'intérieur, ou même pas de A tout cours.
    Dans ce genres de cas, des entités génériques non sauvegardées en base sont utilisées.

    Enfin, la suppression échoue quand j'essaie du supprimer un A ou un B contenant des "enfants", entité par défaut ou non, et même si mon User n'a aucune entité par défaut de définie.
    Elle fonctionne quand je suis l'ordre : je supprime les E d'un B, je peux supprimer le B, etc.

    J'ai encore passé la journée d'hier à me prendre la tête là dessus et ça me rend dingue : c'est comme si les cascades ne se faisaient tout simplement plus.
    Je me demande de plus en plus si le problème ne viendrait pas d'une limite de Doctrine plutôt que d'une mauvaise modélisation de ma part. Je préférerai que ce soit le second cas, au moins je pourrais la corriger.

    En tout cas vos suggestions, même pour modéliser tout ça autrement, sont bienvenues, parce que ça commence à craindre pour moi d'être bloqué là dessus

    Encore merci.
    Javascript est la pornstar des langages de programmation : souple, puissant, tu lui fais faire ce que tu veux, et ça peut finir bien crade.
    ---
    https://www.bgaze.fr

  4. #4
    Membre éprouvé
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    725
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Juin 2011
    Messages : 725
    Points : 1 050
    Points
    1 050
    Par défaut
    les "jointures" (@ORM\OneToOne, @ORM\ManyToOne, ...) n'admettent pas d'argument nullable.
    l'attribut nullable doit être spécifié dans l'annotation joinColumn et pas OneToMany
    http://docs.doctrine-project.org/en/...ref-joincolumn

    finalement le comportement que tu veux c'est que à la suppression d'une Entité
    les champs entity1_id et entity2_id de User qui référence cette entité soit mis à null.
    C'est un onDelete SET NULL au niveau du sql

    as tu essayé quelque chose comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    /**
         * @ORM\OneToOne(targetEntity="\sfCommands\ContentBundle\Entity\Entity")
         * @ORM\JoinColumn(name="entity1_id", referencedColumnName="id", nullable="true", onDelete="SET NULL")
         */
        private $entity1;
    Il faudra rafraichir le schema avec app/console doctrine:schema:update
    Néammoins j'ai déjà eu des problèmes avec ce type de modification sur les cascade qui n'est pas pris en compte. tu peux toujours ajouter ces cascades directement en sql , ou bien reconstruire la base à partir du début.

  5. #5
    Membre habitué Avatar de Soobook
    Homme Profil pro
    Développeur Web
    Inscrit en
    Août 2005
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Réunion

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2005
    Messages : 98
    Points : 149
    Points
    149
    Par défaut
    je n'avais pas encore essayé cette option là, mais toujours la même erreur

    j'ai supprimé puis reconstruit complètement ma base (je bosse sur des fixtures, donc pas de problème), sans succès
    Javascript est la pornstar des langages de programmation : souple, puissant, tu lui fais faire ce que tu veux, et ça peut finir bien crade.
    ---
    https://www.bgaze.fr

  6. #6
    Membre habitué Avatar de Soobook
    Homme Profil pro
    Développeur Web
    Inscrit en
    Août 2005
    Messages
    98
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Réunion

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2005
    Messages : 98
    Points : 149
    Points
    149
    Par défaut


    Ça marche!

    C'est bien le onDelete="SET NULL" qui a débloqué le bazar. Vous trouverez ci-dessous la configuration fonctionnelle, si ça peu faire gagner un peu de temps à quelqun.

    arnooo999, merci beaucoup pour ton aide.
    Ce sont tes précieux conseils qui ont dénoué la crise...

    Bon, ben je résolute du coup!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    #User.
        /**
         * @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Application", mappedBy="user", cascade={"remove"}, orphanRemoval=true)
         * @ORM\OrderBy({"name" = "ASC"})
         */
        protected $applications;
     
        /**
         * @ORM\OneToOne(targetEntity="\sfCommands\ContentBundle\Entity\Entity")
         * @ORM\JoinColumn(name="entity1_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
         */
        private $entity1;
     
        /**
         * @ORM\OneToOne(targetEntity="\sfCommands\ContentBundle\Entity\Entity")
         * @ORM\JoinColumn(name="entity2_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
         */
        private $entity2;
     
    #Application.
        /**
         * @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Bundle", mappedBy="application", cascade={"remove"}, orphanRemoval=true)
         * @ORM\OrderBy({"name" = "ASC"})
         */
        protected $bundles;
     
        /**
         * @ORM\ManyToOne(targetEntity="\sfCommands\UserBundle\Entity\User", inversedBy="applications", cascade={"persist"})
         * @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
         */
        protected $user;
     
    #Bundle.
        /**
         * @ORM\ManyToOne(targetEntity="\sfCommands\ContentBundle\Entity\Application", inversedBy="bundles", cascade={"persist"})
         * @ORM\JoinColumn(name="application_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
         */
        protected $application;
     
        /**
         * @ORM\OneToMany(targetEntity="\sfCommands\ContentBundle\Entity\Entity", mappedBy="bundle", cascade={"remove"}, orphanRemoval=true)
         * @ORM\OrderBy({"name" = "ASC"})
         */
        protected $entitys;
     
    #Entity.
        /**
         * @ORM\ManyToOne(targetEntity="\sfCommands\ContentBundle\Entity\Bundle", inversedBy="entitys", cascade={"persist"})
         * @ORM\JoinColumn(name="bundle_id", referencedColumnName="id", nullable=true, onDelete="SET NULL")
         */
        protected $bundle;
    Javascript est la pornstar des langages de programmation : souple, puissant, tu lui fais faire ce que tu veux, et ça peut finir bien crade.
    ---
    https://www.bgaze.fr

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 7
    Dernier message: 29/11/2010, 17h34
  2. [1.x] data-load après datadump : Integrity constraint violation
    Par rastaferraille dans le forum Symfony
    Réponses: 8
    Dernier message: 07/05/2010, 11h09
  3. [table corrompue] integrity constraints violation
    Par if_zen dans le forum Requêtes
    Réponses: 9
    Dernier message: 17/06/2009, 19h43
  4. Référence circulaire entre projets VS2005
    Par Captain_JS dans le forum C++
    Réponses: 8
    Dernier message: 23/07/2008, 02h42
  5. Réponses: 10
    Dernier message: 19/07/2006, 16h09

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo