Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] Pre-query flush seems not to flush all deletions in the correct order

Il 02/03/2016 15:59, christopher delahunt ha scritto:
Hello Mauro,

I mistyped when I wrote cascade remove - I meant to write cascade merge or cascade persist.  Any references to 'first' could be causing it to be resurrected, not just ones from the 'second' instance's object graph.  I also noticed you are using cascade refresh and lazy relationships - refresh of the referenced entity over a lazy reference will be delayed until it is accessed, potentially wiping out changes made so far.  Something that causes a refresh of firstCollection for instance might get triggered after the remove call but before the flush, and cause firstCollection to still reference first and cause its resurrection in the persistence unit.  I would detail all the references in your object model to the 'first' class and check that one isn't interfering.

If you haven't already, I'd recommend turning on EclipseLink logging and matching statements up to the calls in your code causing them, and trying to determine what is different when the issue occurs vs when it doesn't.  You might also try delaying or removing the constraint, so that you can see if EclipseLink eventually issues the delete so we can see if it is just an ordering issue or if it never does, and so is a resurrection issue in the application references as mentioned before.

Best of luck,
Chris

Hi Chris,
I was "lucky enough" to be able today to reproduce this issue locally!! It's very hard to know what is the correct reproduction path, anyway... What I observed by debugging is this:

FirstCollection firstCollection = first.getFirstCollection();
// do some read-only operations on first
// remove first from the FirstCollection related entities
firstCollection.getFirsts().remove(first);
// delete first
entityManager.remove(first);
// added a flush in the hope this fixes the problem
entityManager.flush(); (***)
// delete the related second instance
entityManager.remove(first.getSecond());
// perform a read query on an entity related to first

Stepping over (***) I saw that the only query that was executed was an UPDATE on the FirstCollection table to update the version and lastUpdated fields!!! The DELETE FROM First was not issued at all!
So, this makes me suspect that the problem is what you are saying:
"Something that causes a refresh of firstCollection for instance might get triggered after the remove call but before the flush, and cause firstCollection to still reference first and cause its resurrection in the persistence unit"

So, I removed the cascade=REFRESH from the relationships in FirstCollection and Third that referenced the First entity.
However, I'm not sure whether it will work now or not because I can't reproduce any more.
In fact, I was able to correctly perform the whole deletion once by using this code:

FirstCollection firstCollection = first.getFirstCollection();
// do some read-only operations on first
// remove first from the FirstCollection related entities
firstCollection.getFirsts().remove(first);
// first flush
entityManager.flush();
// delete first

entityManager.remove(first);
// second flush
entityManager.flush();
// delete the related second instance
entityManager.remove(first.getSecond());
// perform a read query on an entity related to first

that is, by performing a first flush before the remove (this caused just the UPDATE on the FirstCollection table!) and a second one after the remove operation (this one actually performed the DELETE FROM First statement!). But having two flushes like this sounded too dirty for me, so I decided to try the removal of the cascade=REFRESH thing.

I will monitor the situation for some days and let you know. Anyway, if the cascade=REFRESH is the actual problem, this is a really bad beast... especially because I'm really doing nothing in between the remove and the flush. Also, I would expect firstCollections.getFirsts() to be already loaded into memory because it has been accessed several times before and the shared cache is enabled, so I don't even expect it to be lazy initialised when I'm calling that code.  So, there's quite a lot of (black) magic here... :-(
And I can't explain exactly why two flushes before and after the remove would fix the problem.

Mauro

Back to the top