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

ORM PHP Discussion :

Persistance d''entités liées donnant une erreur de violation de contrainte [4.x]


Sujet :

ORM PHP

  1. #1
    Membre averti
    Homme Profil pro
    Inscrit en
    Mai 2004
    Messages
    803
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 803
    Points : 356
    Points
    356
    Par défaut Persistance d''entités liées donnant une erreur de violation de contrainte
    Bonjour,

    Le pensais avoir résolu mon problème, mais ce n'est pas le cas.

    J'ai un formulaire lié à une entité annonce contenant des formulaires embarqués : un formulaire classique lié à un véhicule et un formulaire qui alimente une collection de photos. Lors de l'enregistrement d'une annonce ne contenant qu'une seule photo, tout se passe bien : l'annonce, le véhicule et la photo sont bien enregistrés dans leurs tables respectives.

    Cependant, dès que j'essaie de lier plusieurs photos à l'annonce, j'obtiens l'erreur de violation de contrainte d'intégrité suivante :

    An exception occurred while executing 'INSERT INTO photo (name, id) VALUES (?, ?)' with params ["8435c4ae91b0277c15b669c0a50ced0b.jpeg", null]:

    SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`roadtrip`.`photo`, CONSTRAINT `FK_14B78418BF396750` FOREIGN KEY (`id`) REFERENCES `advert` (`id`))
    Je ne parviens pas à détecter la source du problème. Pourriez-vous m'aider? Voici les sources qui pourraient aider :

    Dans mon entité "Advert" :

    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
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    ...
        /**
         * @ORM\Id()
         * @ORM\GeneratedValue(strategy="AUTO")
         * @ORM\Column(type="integer")
         */
        private $id;
    ...
        /**
         * @ORM\OneToOne(targetEntity="App\Entity\Vehicle", inversedBy="advert", cascade={"persist", "remove"})
         * @ORM\JoinColumn(nullable=false)
         * 
         * @Assert\Type(type="App\Entity\Vehicle")
         * @Assert\Valid()
         */
        private $vehicle;
     
        /**
         * @ORM\OneToMany(targetEntity="App\Entity\Photo", mappedBy="advert", cascade={"persist"}, orphanRemoval=true)
         */
        private $photos;
     
     
        public function __construct() 
    	{
        	$this->photos = new ArrayCollection();
    	}
    ...
        public function getVehicle(): ?Vehicle
        {
            return $this->vehicle;
        }
     
        public function setVehicle(Vehicle $vehicle): self
        {
            $this->vehicle = $vehicle;
            $this->vehicle->setAdvert($this);
     
            return $this;
        }
     
        /**
         * @return Collection|Photo[]
         */
        public function getPhotos(): ArrayCollection
        {
            return $this->photos;
        }
     
        public function setPhotos(ArrayCollection $photos)
        {
            $this->photos = $photos;
        }
     
        public function addPhoto(Photo $photo): self
        {
            if (!$this->photos->contains($photo)) {
                $this->photos[] = $photo;
                $photo->setAdvert($this);
            }
     
            return $this;
        }
    ...
    Dans mon entité "Vehicle" :

    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
    ...
        /**
         * @ORM\Id()
         * @ORM\GeneratedValue()
         * @ORM\Column(type="integer")
         */
        private $id;
    ...
        /**
         * @ORM\OneToOne(targetEntity="App\Entity\Advert", mappedBy="vehicle", cascade={"persist", "remove"})
         */
        private $advert;
    ...
        public function getAdvert(): ?Advert
        {
            return $this->advert;
        }
     
        public function setAdvert(Advert $advert): self
        {
            $this->advert = $advert;
     
            // set the owning side of the relation if necessary
            if ($this !== $advert->getVehicle()) {
                $advert->setVehicle($this);
            }
     
            return $this;
        }
    ...
    Dans mon entité "Photo" :

    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
    ...
        /**
         * @ORM\Id()
         * @ORM\GeneratedValue(strategy="AUTO")
         * @ORM\Column(type="integer")
         */
        private $id;
    ...
        /**
         * @ORM\ManyToOne(targetEntity="App\Entity\Advert", inversedBy="photos")
         * @ORM\JoinColumn(name="id", referencedColumnName="id")
         */
        private $advert;
    ...
        public function getAvert(): ?Advert
        {
            return $this->advert;
        }
     
        public function setAdvert(Advert $advert): self
        {
    		$this->advert = $advert;
     
            return $this;
    	}
    ...
    Et enfin, dans mon controller :

    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
    52
    53
    54
    55
    56
    57
    ...
        public function advertForm(Advert $advert = null, Request $request, ObjectManager $manager){
     
            if (!$advert) {
                $advert = new Advert();
                $vehicle = new Vehicle();
                $advert->setVehicle($vehicle);
                /*$photo1 = new Photo();
                $photo2 = new Photo();
     
                $vehicle->setAdvert($advert);
            }
     
            $form = $this->createForm(AdvertType::class, $advert);
            $form->handleRequest($request);
     
            if ($form->isSubmitted() && $form->isValid()) {
     
                //If it's a new advert, date assignment and expiration date assignement
                $now = new \DateTime('now');
     
                $advert->setCreatedAt($now);
                $advert->SetExpiresAt($now->add(new DateInterval($this->getParameter('advert_active_duration'))));
     
                $photos = $advert->getPhotos();
     
                foreach ($photos as $photo) {
     
                    $advert->addPhoto($photo);
     
                    // If no file is set, do nothing
                    if (null !== $photo->getFile())
                    {               
     
                        $photo->setName(md5(uniqid()) . '.' . $photo->getFile()->guessExtension());
                            
                        try 
                        {
                            $photo->getFile()->move($this->getParameter('photos_directory'), $photo->getName());
                        } 
                        catch (FileException $e) 
                        {
                            // ... handle exception if something happens during file upload
                        }
     
                    }
     
                }           
     
                $manager->persist($advert);
                $manager->flush();
     
            }
     
            return $this->render('road_trip/createAdvert.html.twig', ['formAdvert' => $form->createView(), 'editMode' => $advert->getId() !== null]);        
        }
    ...
    Merci d'avance pour votre aide!

    Edit 1 :

    J'ai remarqué que la colonne "advert_id" n'était pas créée dans ma table "photo". J'ai donc modifié l'attribut "advert" comme suit dans ma classe "Photo" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
        /**
         * @ORM\ManyToOne(targetEntity="App\Entity\Advert", inversedBy="photos")
         * @ORM\JoinColumn(nullable=false)
         */
        private $advert;
    J'ai supprimé mes tables et mes fichiers de migration et j'ai refait une migration : la colonne "advert_id" est maintenant bien créée.

    Lorsque je tente d'insérer une annonce, j'ai maintenant cette erreur :

    An exception occurred while executing 'INSERT INTO photo (name, advert_id) VALUES (?, ?)' with params ["025e2ba9ec1f70a88c18546ef202fd68.jpeg", null]:

    SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'advert_id' cannot be null
    Edit 2 :

    En supprimant "* @ORM\JoinColumn(nullable=false)" et en permettant le null dans le champ correspondant dans ma table, ça fonctionne correctement. Cependant, je ne trouve pas ça logique ni propore, du fait qu'une photo doit impérativement être liée à une annonce. Quelqu'un a une idée?

  2. #2
    Membre extrêmement actif
    Avatar de Sodium
    Femme Profil pro
    Développeuse web
    Inscrit en
    Avril 2014
    Messages
    2 324
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeuse web

    Informations forums :
    Inscription : Avril 2014
    Messages : 2 324
    Points : 2 006
    Points
    2 006
    Billets dans le blog
    1
    Par défaut
    D'après ce que je comprends, tu utilises la colonne "id" de ta table photos comme clé étrangère vers la table advert, ce qui ne peut logiquement que causer une erreur lorsque deux photos sont liées à la même advert puisqu'il y a probablement une constraint unique sur la colonne id servant à la base de clé primaire.
    Tu devrais retirer ton paramétrage JoinColumn et laisser Symfony gérer ça.

    Pour ton deuxième problème il manque le code d'ajout de photo dans la base de données, à moins qu'il soit en commentaire mais dans ce cas on ne peut pas devenir de quoi il s'agit. Tu devrais retirer tout le code inutilisé lorsque tu postes sur le forum pour qu'on puisse se focaliser sur la résolution du problème.

  3. #3
    Membre averti
    Homme Profil pro
    Inscrit en
    Mai 2004
    Messages
    803
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 803
    Points : 356
    Points
    356
    Par défaut
    Merci beaucoup pour ton intérêt.

    De fait, j'avais retiré
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    * @ORM\JoinColumn(nullable=false)
    , mais ça me donnait alors l'erreur

    An exception occurred while executing 'INSERT INTO photo (name, advert_id) VALUES (?, ?)' with params ["988d063e11e9856c6c068697d2ad489e.jpeg", null]:

    SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'advert_id' cannot be null
    Via PhpAdmin, je dois alors aller dans ma ta table "photo" pour indiquer que le champ "advert_id" peut être null pour que ça fonctionne. Cependant, je ne trouve pas ça logique étant donné qu'une photo doit être impérativement liée à une annonce (advert_id ne doit jamais être null). Mais en faisant comme cela, l'annonce est bien insérée dans la table "advert" et les photos dans la table "photo" qui comporte bien le champ "advert_id" correctement complété avec l'id de l'annonce à laquelle elles sont liées (de fait, une annonce peut comporter plusieurs photos).

    Je ne comprends pas dès lors pas pourquoi cela ne fonctionne pas quand le champ "advert_id" est indiqué comme ne pouvant pas être null.

    CORRECTION : mes champs advert_id sont à null, ce qui ne m'arrange pas du tout!

  4. #4
    Membre extrêmement actif
    Avatar de Sodium
    Femme Profil pro
    Développeuse web
    Inscrit en
    Avril 2014
    Messages
    2 324
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeuse web

    Informations forums :
    Inscription : Avril 2014
    Messages : 2 324
    Points : 2 006
    Points
    2 006
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par dubitoph Voir le message
    Merci beaucoup pour ton intérêt.

    De fait, j'avais retiré
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    * @ORM\JoinColumn(nullable=false)
    , mais ça me donnait alors l'erreur
    Je faisais référence à la ligne suivante : @ORM\JoinColumn(name="id", referencedColumnName="id")

    Citation Envoyé par dubitoph Voir le message
    Via PhpAdmin, je dois alors aller dans ma ta table "photo" pour indiquer que le champ "advert_id" peut être null pour que ça fonctionne. Cependant, je ne trouve pas ça logique étant donné qu'une photo doit être impérativement liée à une annonce (advert_id ne doit jamais être null). Mais en faisant comme cela, l'annonce est bien insérée dans la table "advert" et les photos dans la table "photo" qui comporte bien le champ "advert_id" correctement complété avec l'id de l'annonce à laquelle elles sont liées (de fait, une annonce peut comporter plusieurs photos).
    Ca devrait marcher sans soucis si tu as bien lié ta photo à une advert avant de tenter de l'insérer en bdd, mais c'est pour ça qu'on a besoin de voir le code qui ajoute une photo dans ton controller.

  5. #5
    Membre averti
    Homme Profil pro
    Inscrit en
    Mai 2004
    Messages
    803
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 803
    Points : 356
    Points
    356
    Par défaut
    Correction, mes champs advert_id sont à null, ce qui ne m'arrange pas du tout :-)

    Etant donné qu'il y a un cascade={"persist"}, je n'ai pas de code spécifique d'insertion des photos. C'est Symfony qui s'en charge, selon moi...

  6. #6
    Membre averti
    Homme Profil pro
    Inscrit en
    Mai 2004
    Messages
    803
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 803
    Points : 356
    Points
    356
    Par défaut
    J'ai apparemment trouvé : j'ai ajouté
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $photo->setAdvert($advert);
    dans la boucle de la fonction de mon controller et j'ai remis le champ "advert_id" comme ne pouvant pas être null et ça à l'air de fonctionner.

    Merci pour ton temps et ton aide ;-)

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 14/02/2017, 17h32
  2. Réponses: 12
    Dernier message: 25/11/2007, 12h29
  3. Réponses: 4
    Dernier message: 09/08/2006, 22h28
  4. [DAO VBA] Récupérer une erreur de violation de clé
    Par Caroline1 dans le forum Access
    Réponses: 5
    Dernier message: 28/04/2006, 17h39
  5. [MySQL] login/mdp donnant une erreur 1 coup sur 2
    Par vincedjs dans le forum PHP & Base de données
    Réponses: 15
    Dernier message: 16/03/2006, 14h20

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