doctrine / orm

Doctrine Object Relational Mapper (ORM)
https://www.doctrine-project.org/projects/orm.html
MIT License
9.91k stars 2.51k forks source link

PersistentCollection::clear() and removeElement() with orphanRemoval #6509

Open steevanb opened 7 years ago

steevanb commented 7 years ago

Hi !

I have a simple User entity, linked to Comment by oneToMany, with orphanRemoval:

class User
{
    protected $comments;

    public function __construct()
    {
        $this->comments = new ArrayCollection();
    }

    public function getComments(): Collection
    {
        return $this->comments;
    }

    public function addComment(Comment $comment): self
    {
        if ($this->comments->contains($comment) === false) {
            $this->comments->add($comment);
            $comment->setUser($this);
        }

        return $this;
    }
}
class Comment
{
    protected $user;

    public function setUser(?User $user): self
    {
        $this->user = $user;

        return $this;
    }

    public function getUser(): ?User
    {
        return $this->user;
    }
}

if i call that:

$user = $repositoryUser->find(1);
foreach ($user->getComments() as $comment) {
    $user->getComments()->removeElement($comment);
    $user->addComment($comment);
}

$manager->flush();

or that:

$comment = $user->getComments()->first();
$user->getComments()->clear();
$user->addComment($comment);

$manager->flush();

Finally, Comment entity will be deleted.

Why ? Cause in PersistentCollection::clear() and removeElement(), orphanRemoval will add your deleted entity in UnitOfWork::$orphanRemovals. flush() will read UnitOfWork::$orphanRemovals, and delete all entities, although they are deleted then added See https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/PersistentCollection.php#L395 and https://github.com/doctrine/doctrine2/blob/master/lib/Doctrine/ORM/PersistentCollection.php#L560

How can i delete then add same entity, with orphanRemoval ?

alcaeus commented 7 years ago

Cross-referencing doctrine/mongodb-odm#1248, where we solved the same issue by unscheduling orphan removal in PersistentCollection::add

steevanb commented 7 years ago

Looks good, but why this is not fixed for every databases ? Like MySQL ?

alcaeus commented 7 years ago

@steevanb Because I only maintain ODM where I originally found the issue. I haven't used an SQL based database in years. I'll try to port the fix over to ORM.

steevanb commented 7 years ago

Ok thanks !

lcobucci commented 7 years ago

@steevanb could you please send us a PR with a functional test that reproduces this behaviour? Sending just an example doesn't give us the complete overview of things and why it fails. You can find examples on https://github.com/doctrine/doctrine2/tree/971c40002522cfebe58d80aff21eef9fe439fa60/tests/Doctrine/Tests/ORM/Functional