DDC-635: Snapshot is not being created after loadManyToManyCollection done hydrating #785

Closed
opened 2026-01-22 12:50:19 +01:00 by admin · 5 comments
Owner

Originally created by @doctrinebot on GitHub (Jun 13, 2010).

Jira issue originally created by user sammysnake:

Bug: MySQL error "SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1-1' for key 1 " produced by flushing a hydrated entity after adding an entity to it in many-to-many relationship.

My Solution: BasicEntityPersister.php
function loadManyToManyCollection(ManyToManyMapping $assoc, $sourceEntity, PersistentCollection $coll)
704a705

          $coll->takeSnapshot();

Reproduce:

// Client Code
// Step1) create Phone Number, Create Person, add phone to person (one-to-many), flush

$phone = new Models\PhoneNumber();
$phone->setNumber('123-1234');
$em->persist($phone);

$person = new Models\Person();
$person->getPhoneNumbers()->add($phone);
$em->persist($person);
$em->flush();
// Client Code
// Step2) pull newly created Person, Create new phone number, add phone to person, flush

// This code will produce error 
// Message: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1-1' for key 1 
// This is because $_snapshot in PersistentCollection is not being initalized after hydrating


$person = $em->getRepository('Models\Person')->findOneBy(array('id' => 1));

$phone = new Models\PhoneNumber();
$phone->setNumber('333-1234');
$em->persist($phone);

$person->getPhoneNumbers()->add($phone);
$em->persist($person);

$em->flush();

Entities Used..

<?php

namespace Models;

use Doctrine\Common\Collections\ArrayCollection;

/****
 * @Entity @Table(name="person")
 */

class Person
{

    /****
     * @Id @Column(name="id", type="integer")
     * @GeneratedValue(strategy="AUTO")
     */
    private $id;    

    /****
    * @ManyToMany(targetEntity="Models\PhoneNumber")
    * @JoinTable(name="person_phonenumbers",
    *      joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
    *      inverseJoinColumns={@JoinColumn(name="phone_id", referencedColumnName="id")}
    *      )
    */   
    private $phoneNumbers;

    public function **construct()
    {
        $this->phoneNumbers = new ArrayCollection();
    }

    public function getId()
    {
        return $this->id;
    }

    public function getPhoneNumbers()
    {
        return $this->phoneNumbers;
    }


}
<?php
namespace Models;

/****
 * @Entity @Table(name="phonenumber")
 */

class PhoneNumber
{

    /****
     * @Id @Column(name="id", type="integer")
     * @GeneratedValue(strategy="AUTO")
     */
    private $id;    

    /*** @Column(type="string", length=50) **/
private $number;

    public function setNumber($number)  
    {
    $this->number = $number;    
    }       
}
Originally created by @doctrinebot on GitHub (Jun 13, 2010). Jira issue originally created by user sammysnake: Bug: MySQL error "SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1-1' for key 1 " produced by flushing a hydrated entity after adding an entity to it in many-to-many relationship. My Solution: BasicEntityPersister.php function loadManyToManyCollection(ManyToManyMapping $assoc, $sourceEntity, PersistentCollection $coll) 704a705 > ``` > $coll->takeSnapshot(); > ``` Reproduce: ``` // Client Code // Step1) create Phone Number, Create Person, add phone to person (one-to-many), flush $phone = new Models\PhoneNumber(); $phone->setNumber('123-1234'); $em->persist($phone); $person = new Models\Person(); $person->getPhoneNumbers()->add($phone); $em->persist($person); $em->flush(); ``` ``` // Client Code // Step2) pull newly created Person, Create new phone number, add phone to person, flush // This code will produce error // Message: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1-1' for key 1 // This is because $_snapshot in PersistentCollection is not being initalized after hydrating $person = $em->getRepository('Models\Person')->findOneBy(array('id' => 1)); $phone = new Models\PhoneNumber(); $phone->setNumber('333-1234'); $em->persist($phone); $person->getPhoneNumbers()->add($phone); $em->persist($person); $em->flush(); ``` Entities Used.. ``` <?php namespace Models; use Doctrine\Common\Collections\ArrayCollection; /**** * @Entity @Table(name="person") */ class Person { /**** * @Id @Column(name="id", type="integer") * @GeneratedValue(strategy="AUTO") */ private $id; /**** * @ManyToMany(targetEntity="Models\PhoneNumber") * @JoinTable(name="person_phonenumbers", * joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")}, * inverseJoinColumns={@JoinColumn(name="phone_id", referencedColumnName="id")} * ) */ private $phoneNumbers; public function **construct() { $this->phoneNumbers = new ArrayCollection(); } public function getId() { return $this->id; } public function getPhoneNumbers() { return $this->phoneNumbers; } } ``` ``` <?php namespace Models; /**** * @Entity @Table(name="phonenumber") */ class PhoneNumber { /**** * @Id @Column(name="id", type="integer") * @GeneratedValue(strategy="AUTO") */ private $id; /*** @Column(type="string", length=50) **/ private $number; public function setNumber($number) { $this->number = $number; } } ```
admin added the Bug label 2026-01-22 12:50:19 +01:00
admin closed this issue 2026-01-22 12:50:20 +01:00
Author
Owner

@doctrinebot commented on GitHub (Jul 4, 2010):

Comment created by @beberlei:

I cannot reproduce this, can you try to create a PHPUnit testcase similar to those in the tests/Doctrine/Tests/ORM/Functional/Ticket folder that shows the behaviour you described?

@doctrinebot commented on GitHub (Jul 4, 2010): Comment created by @beberlei: I cannot reproduce this, can you try to create a PHPUnit testcase similar to those in the **tests/Doctrine/Tests/ORM/Functional/Ticket** folder that shows the behaviour you described?
Author
Owner

@doctrinebot commented on GitHub (Jul 4, 2010):

Comment created by @beberlei:

A test of the following kind does not fail, works correctly:

    public function testRetrieveManyToManyAndAddMore()
    {
        $user = $this->addCmsUserGblancoWithGroups(2);

        $group = new CmsGroup();
        $group->name = 'Developers_Fresh';
        $this->_em->persist($group);
        $this->_em->flush();

        $this->_em->clear();

        $freshUser = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $user->getId());
        $freshUser->addGroup($group);

        $this->_em->flush();
        $this->_em->clear();

        $freshUser = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $user->getId());
        $this->assertEquals(3, count($freshUser->getGroups()));
    }
@doctrinebot commented on GitHub (Jul 4, 2010): Comment created by @beberlei: A test of the following kind does not fail, works correctly: ``` public function testRetrieveManyToManyAndAddMore() { $user = $this->addCmsUserGblancoWithGroups(2); $group = new CmsGroup(); $group->name = 'Developers_Fresh'; $this->_em->persist($group); $this->_em->flush(); $this->_em->clear(); $freshUser = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $user->getId()); $freshUser->addGroup($group); $this->_em->flush(); $this->_em->clear(); $freshUser = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $user->getId()); $this->assertEquals(3, count($freshUser->getGroups())); } ```
Author
Owner

@doctrinebot commented on GitHub (Jul 4, 2010):

Comment created by @beberlei:

Its correct that no snapshot is made at that point, the lazy load of the collection would be triggered this way, which would be very bad!

The "takeSnapshot" method is called during PersistentCollection::initialize()

@doctrinebot commented on GitHub (Jul 4, 2010): Comment created by @beberlei: Its correct that no snapshot is made at that point, the lazy load of the collection would be triggered this way, which would be very bad! The "takeSnapshot" method is called during PersistentCollection::initialize()
Author
Owner

@doctrinebot commented on GitHub (Jul 14, 2010):

Comment created by sammysnake:

Unable to reproduce on beta2, magically fixed :)

@doctrinebot commented on GitHub (Jul 14, 2010): Comment created by sammysnake: Unable to reproduce on beta2, magically fixed :)
Author
Owner

@doctrinebot commented on GitHub (Jul 14, 2010):

Issue was closed with resolution "Invalid"

@doctrinebot commented on GitHub (Jul 14, 2010): Issue was closed with resolution "Invalid"
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#785