DDC-2200: Duplicates returned while accessing associations from @PostPersist callback #2769

Open
opened 2026-01-22 14:03:03 +01:00 by admin · 0 comments
Owner

Originally created by @doctrinebot on GitHub (Dec 15, 2012).

Originally assigned to: @beberlei on GitHub.

Jira issue originally created by user breathe:

When creating a new Post and adding it to a collection in an existing Thread (i.e. loaded from the database), referencing Thread's posts collection in Post's @PostPersist callback returns the Post twice. To clarify, this only happens when Thread was previously persisted. If I'm creating a new Thread object the code works as expected. I've included some sample code to better illustrate my issue.

I don't know if this is a bug, or if I'm doing something that I shouldn't be, but I couldn't find this limitation mentioned in the documentation, and this seems to go against the expected behavior.

Here are my sample entities:


/****
 * @Entity
 * @Table(name="thread")
 */
class Thread
{
    /**** 
     * @Id
     * @GeneratedValue
     * @Column(type="integer")
     */
    protected $id;

    /**** 
     * @OneToMany(targetEntity="Post", mappedBy="thread", cascade={"persist", "remove"})
     */
    protected $posts;

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

    public function getPosts() {
        return $this->posts->toArray();
    }   

    public function addPost(Post $post) {
        $post->setThread($this);
        $this->posts->add($post);
    }   
}

/****
 * @Entity
 * @Table(name="post")
 * @HasLifecycleCallbacks
 */
class Post
{
    /**** 
     * @Id
     * @GeneratedValue
     * @Column(type="integer")
     */
    protected $id;

    /**** 
     * @ManyToOne(targetEntity="Thread", inversedBy="posts")
     * @JoinColumn(name="thread_id", referencedColumnName="id")
     */
    protected $thread;

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

    /**** 
     * @PostPersist
     */
    public function onPostPersist() {
        $posts = $this->thread->getPosts();
        foreach ($posts as $post) {
            echo 'id: ' . $post->getId() . ' type: ' . get_class($alert) . '<br />';
        }   
    }

    public function setThread(Thread $thread) {
        $this->thread = $thread;
    }   
}

And the calling code:


// Grab an existing thread.
$thread = $em->getReference('Thread', 1); 
$thread->addPost(new Post());
$em->flush();

This outputs:


id: 1 type: Post
id: 1 type: Post

Alternatively:


// Create a new thread.
$thread = new Thread()
$thread->addPost(new Post());
$em->persist($thread);
$em->flush();

This outputs:


id: 1 type: Post

Originally created by @doctrinebot on GitHub (Dec 15, 2012). Originally assigned to: @beberlei on GitHub. Jira issue originally created by user breathe: When creating a new Post and adding it to a collection in an **existing** Thread (i.e. loaded from the database), referencing Thread's posts collection in Post's @PostPersist callback returns the Post twice. To clarify, this only happens when Thread was previously persisted. If I'm creating a new Thread object the code works as expected. I've included some sample code to better illustrate my issue. I don't know if this is a bug, or if I'm doing something that I shouldn't be, but I couldn't find this limitation mentioned in the documentation, and this seems to go against the expected behavior. Here are my sample entities: ``` /**** * @Entity * @Table(name="thread") */ class Thread { /**** * @Id * @GeneratedValue * @Column(type="integer") */ protected $id; /**** * @OneToMany(targetEntity="Post", mappedBy="thread", cascade={"persist", "remove"}) */ protected $posts; public function **construct() { $this->posts = new ArrayCollection(); } public function getPosts() { return $this->posts->toArray(); } public function addPost(Post $post) { $post->setThread($this); $this->posts->add($post); } } /**** * @Entity * @Table(name="post") * @HasLifecycleCallbacks */ class Post { /**** * @Id * @GeneratedValue * @Column(type="integer") */ protected $id; /**** * @ManyToOne(targetEntity="Thread", inversedBy="posts") * @JoinColumn(name="thread_id", referencedColumnName="id") */ protected $thread; public function getId() { return $this->id; } /**** * @PostPersist */ public function onPostPersist() { $posts = $this->thread->getPosts(); foreach ($posts as $post) { echo 'id: ' . $post->getId() . ' type: ' . get_class($alert) . '<br />'; } } public function setThread(Thread $thread) { $this->thread = $thread; } } ``` And the calling code: ``` // Grab an existing thread. $thread = $em->getReference('Thread', 1); $thread->addPost(new Post()); $em->flush(); ``` This outputs: ``` id: 1 type: Post id: 1 type: Post ``` Alternatively: ``` // Create a new thread. $thread = new Thread() $thread->addPost(new Post()); $em->persist($thread); $em->flush(); ``` This outputs: ``` id: 1 type: Post ```
admin added the Bug label 2026-01-22 14:03:03 +01:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#2769