mirror of
https://github.com/doctrine/orm.git
synced 2026-03-23 22:42:18 +01:00
computeChangeSet of class UnitOfWork rewrites not flushed changes #7121
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @ioSeoGio on GitHub (Mar 14, 2023).
Bug Report
Summary
Using method computeChangeSets of class UnitOfWork, Im updating list of entities that going to be inserted/changed/deleted. At this point my entities still not flushed to database, but persisted to entityManager. After this, if I try to edit affected entity and flush - UnitOfWork runs computeChangeSets again and rewrites old change list ($this->entityChangeSets[$oid] in UnitOfWork). During flushing there are no enough data, so Im getting error like:
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens, because old data was lost.Current behavior
method computeChangeSets of class UnitOfWork rewrites old change list, even if entity was not flushed into db
How to reproduce
Create object of entity, persist to entityManager, call method computeChangeSets of class UnitOfWork, change something in object, call flush method of entityManager
Expected behavior
method computeChangeSets is public, so UnitOfWork must take it into account, because it can be used in client code. Method should not rewrites, but merge old and new entity change list.
Possible solution:
https://github.com/doctrine/orm/blob/3.0.x/lib/Doctrine/ORM/UnitOfWork.php#L715
Change:
To:
@mpdude commented on GitHub (Mar 15, 2023):
I am not really sure what the intended use case for that method is. A Google search turned up this one: https://github.com/doctrine/orm/issues/5945
Can you provide example code to illustrate your use case?
@ioSeoGio commented on GitHub (Mar 17, 2023):
I used this method to get list of entities that gonna be persisted/removed/updated, like this:
$this->entityManager->computeChangeSets();
$unitOfWork = $this->entityManager->getUnitOfWork();
$toInsert = $unitOfWork->getScheduledEntityInsertions();
$toUpdate = $unitOfWork->getScheduledEntityUpdates();
$toDelete = $unitOfWork->getScheduledEntityDeletions();
...
All is working properly until I dont want to change this entities before flushing
@johndodev commented on GitHub (Jan 5, 2024):
I have the "same" problem (I have no exceptions). There is a simple example :
So, the "problem" is if the entity change again after the custom call of "computeChangeSets", the entitymanager lost previous changes. I think the possible solution of @ioSeoGio seems ok, I don't see potential bug.
My use case is, I need to get the changeset of an entity on a controller (or whatever, I mean not in a preUpdateEvent), and if not empty, add a relation to the entity. Then the code after may update it again, and I don't care. Please don't ask more, it's simplified here.
@DavideBicego commented on GitHub (Sep 26, 2024):
If you use
$uow->computeChangeSet(...)instead of$uow->computeChangeSets()you can call$uow->recomputeSingleEntityChangeSet(...)before flushing.@Qronicle commented on GitHub (Feb 13, 2025):
I also ran into this issue today. I know we're basically abusing the unit of work, but I still feel like it would be nice to be able to get the changeSet without having to resort to a "solution" like using
recomputeSingleEntityChangeSet. Using the latter, you're basically moving the problem to other potential code that wants to update the entity later.If we'd have a function like
discardComputedChangeSetsordiscardComputedEntityChangeSet, we could nicely clean the unit of work and pretend like nothing happened :) (Not sure how feasible that is though.)(Edit: for now I just do a single query that fetches the persisted value, and compare that to what's in the entity to avoid this alltogether.)
@haukesomm commented on GitHub (Apr 29, 2025):
I'm having the same problem as well. I'm currently resorting to the
UnitOfWorkto determine what the changes would be if I flushed my work and determine further steps based on that.For this use case, an API allowing me to "virtually" compute a change set without it having an effect on the database or unit of work would be ideal. So in a similar way of @Qronicle 's solution (but kind of the other way around) this would incorporate a
UnitOfWork::computeChangeSetsandUnitOfWork::applyChangeSetsmethod, where to former one returns a change set and the latter one takes one and applies it to the unit of work.