Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flush could delete entities before inserting new ones #5742

Open
MacDada opened this issue Mar 26, 2016 · 16 comments
Open

Flush could delete entities before inserting new ones #5742

MacDada opened this issue Mar 26, 2016 · 16 comments

Comments

@MacDada
Copy link

MacDada commented Mar 26, 2016

I have a unique (not PK) column. I need to remove old entities first and then add new ones (replacements).

Yeah, I've seen this: #5368

But I've also seen a "could be done" solution:

A function "setShouldPerformDeletesFirst" as described in http://docs.oracle.com/cd/B31017_01/web.1013/b28218/uowadv.htm#i1137484 would be very useful in those cases.

What I propose, is that this gets implemented. From the dev point of view, it would be cool, if one could do that like this:

* @ORM\OneToMany(targetEntity="Whatever", mappedBy="Me", cascade={"persist"}, orphanRemoval=true, removeBeforeAdd=true)

@ureimers
Copy link
Contributor

ureimers commented Dec 2, 2016

I'm not quite sure if removeBeforeAdd should only be available on relations. You could easily think of a case where you replace entity A with B with both having the same uniquely constrained fields.

@fsmeier
Copy link

fsmeier commented Apr 29, 2018

+1 here

@johandouma
Copy link

johandouma commented Nov 18, 2020

+1.
This issue seems related to #6776, in case other people are searching. And #2310, #7721, #5109 (this last one has a few comments with lots of upvotes too) - this really is a larger issue that IMO should be attended to, a removeBeforeAdd option may only be a bandaid

@SmasherHell
Copy link

SmasherHell commented Feb 24, 2022

+1 That is quite a challenge to respect OCP when doctrine removes "merge". There is no way to update an object from a clone within a transaction. How to have a separation of concerns between logic and persistance when we must flush a state in the middle of logic

@hhamon
Copy link

hhamon commented Mar 10, 2022

I faced this issue as well on my client project. We had to remove the SQL unique constraint on the table to ensure the Doctrine SQL transaction can be complete. But ideally we would need both the SQL unique constraint (to always ensure consistency in the database) and in the SQL transaction when Doctrine flush statement is performed.

@mpdude
Copy link
Contributor

mpdude commented Jun 28, 2023

@SmasherHell I am not sure if it would support your use case – probably it may be difficult to deal with two entities at the same time that share the same primary key value, and to have one replace the other in a single transaction.

The OP request is more about being able to meet other (non-primary key) constraints.

mpdude added a commit to mpdude/doctrine2 that referenced this issue Jun 28, 2023
There are a few requests (doctrine#5742, doctrine#5368, doctrine#5109, doctrine#6776) that ask to change the order of operations in the UnitOfWork to perform "deletes before inserts", or where such a switch appears to solve a reported problem.

I don't want to say that this is not doable. But this PR at least adds two tricky examples where INSERTs need to be done before an UPDATE can refer to new database rows; and where the UPDATE needs to happen to release foreign key references to other entities before those can be DELETEd.

So, at least as long as all operations of a certain type are to be executed in blocks, this example allows no other order of operations than the current one.
@mpdude
Copy link
Contributor

mpdude commented Jun 28, 2023

#10809 adds an example that shows why we cannot – at least not, in general – change the current order of operations in the UoW.

mpdude added a commit to mpdude/doctrine2 that referenced this issue Jun 29, 2023
There are a few requests (doctrine#5742, doctrine#5368, doctrine#5109, doctrine#6776) that ask to change the order of operations in the UnitOfWork to perform "deletes before inserts", or where such a switch appears to solve a reported problem.

I don't want to say that this is not doable. But this PR at least adds two tricky examples where INSERTs need to be done before an UPDATE can refer to new database rows; and where the UPDATE needs to happen to release foreign key references to other entities before those can be DELETEd.

So, at least as long as all operations of a certain type are to be executed in blocks, this example allows no other order of operations than the current one.
@maddanio
Copy link

may I ask why the order is not simply preserved? that would likely be the expectation of the library user. doctrine reordering actions is susprising.

@mpdude
Copy link
Contributor

mpdude commented Aug 17, 2023

No, that’s the promise given by the ORM: You tell it which entities you want to have tracked, and when you call flush(), it executes the (minimum amount of) queries it takes to persist changes.

That includes giving the ORM some freedom to order operations as it sees fit.

Additional unique constraints in the database as we‘re discussing here may interfere with that. They prevent the ORM from doing things in the planned order, through restrictions it cannot foresee and/or efficiently include in the commit order computation.

@maddanio
Copy link

can you give an example where not keeping the order is neccessary to fulfil that promise?

@greg0ire
Copy link
Member

@maddanio you can read up on this at #10547

@maddanio
Copy link

hmm, but i don't quite see how this completely prevents keeping ordering. yes in some situations things need to be reordered, but if one really only does the required reorderings and keeps things otherwise stable I think most of the problems would go away, or am I overlookling something?

@mpdude
Copy link
Contributor

mpdude commented Aug 17, 2023

but if one really only does the required reorderings and keeps things otherwise stable I think most of the problems would go away

I think that is how it is implemented. If you have a reproducible case that indicates otherwise, I’d be happy to look into it as a potential bug

@maddanio
Copy link

Ah ok, well need to find out how to reduce this. But basically i am removing an entity and then adding another one with the same primary id. Adding a flush between makes it work. Hmm, but maybe we are using a too old doctrine version. Will check

@mpdude
Copy link
Contributor

mpdude commented Aug 19, 2023

You’re even describing a special case where the unique constraint is for the primary key, not just for any other column.

You must be using application-provided IDs, otherwise this kind of ID reuse would not happen.

This is not going to work for at least one reason apart from the order of operations during flush: Since the identity map refers to entities (object instances) by means of the ID, there will be a collision already when you try to add the one object and have the other one set up for removal.

@maddanio
Copy link

Is there then a stable way to completely replace an object?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants