These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 
Author Message
 Post subject: manual delete + cascade delete = StaleStateException
PostPosted: Mon Mar 17, 2008 6:30 pm 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
Hibernate version: 1.2.1.GA

I have two entities mapped such that one has a collection of the other. The collection item entity has a reference back to the owning entity. The cascade is set up as all-delete-orphan.

I have this sequence of events:

1. Session1 is created, entities are queried, and the session1 is disposed.
2. A collection item is removed from the owning entity's collection.
3. The collection item's reference to the owning entity is cleared.
4. The owning entity is modified.
5. Session2 is created to save changes.
6. The collection item is manually deleted via session2.Delete().
7. Session2 is manually flushed.
8. The owning item is manually updated via session2.Update().
9. Session2 is manually flushed again.

I then get "StaleStateException: Unexpected row count: 0; expected: 1".

What appears to happen is that NHibernate attempts to delete the collection item twice -- once for the manual Delete() and once for the implicit cascade.

Shouldn't cascade deletes be smart enough to know that an entity it's trying to delete due to cascade rules has already been deleted earlier in the session?


Top
 Profile  
 
 Post subject: Re: manual delete + cascade delete = StaleStateException
PostPosted: Wed Mar 19, 2008 11:28 am 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
That's the delete-orphan part that does this for you and if I recall correctly I read somewhere in the document where it says you really need to know an entity in a collection is not being manipulated somewhere out of scope of the collection it belongs to.


Farzad-


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 20, 2008 9:44 am 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
Maybe we'll have to get rid of the delete-orphan cascade. We have cascade deletes at the database level for everything mapped for NHibernate to cascade delete, and we need to keep support for manual deletions of dependent entities combined with other updates to their owners in the same session. For us, manual deletes will occur as often or more often than cascaded deletes.

If you have cascade deleting at the database level, is there even a reason to have cascade delete in the NHibernate mapping? I.e. is it needed to prevent NHibernate from getting confused about what the database may do that it won't know about?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 20, 2008 4:02 pm 
Expert
Expert

Joined: Wed Apr 11, 2007 11:39 am
Posts: 735
Location: Montreal, QC
Nels_P_Olsen wrote:
If you have cascade deleting at the database level, is there even a reason to have cascade delete in the NHibernate mapping? I.e. is it needed to prevent NHibernate from getting confused about what the database may do that it won't know about?



In certain use case Hibernate definitely has an assumption that it knows the truth about database, such as it complains if it goes to update something in database and it is not there anymore. I do understand that cascade deletes in a database level can be very useful but you need to treat hibernate in these cases. Definitely you can not mix this with any other delete option in hibernate. However, with selects it should be ok since hibernate can ignore missing relations. This become a lot more complicated if a second level cache is used.



Farzad-


Top
 Profile  
 
 Post subject:
PostPosted: Wed Apr 09, 2008 6:03 pm 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
The problem still seems to be NHibernate's fault. It should keep track of what has been explicitly deleted in a session so as not to get confused about expectations of its implicit actions (i.e. cascade deletes).

It sounds very restrictive to say that any use of cascade delete mapping on entities with bidirectional references forbids any explicit deletion of those entities subject to cascade deleting. We want to use explicit deletion under normal circumstances and intend cascade deleting to function as a safety net. The safety net shouldn't prevent you from doing the primary operation.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 10, 2008 11:52 am 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
Thinking about this a little more, there seems to be two separate problems. The problem as reported is that an NHibernate session doesn't keep track of explicit deletes, and so gets confused when an implicit (cascaded) delete "fails" because the entity is no longer in the database. However, even with this issue aside, if NHibernate tries to delete something from the database and it's not there for any reason (whether it forgot that it already deleted it, or it was deleted externally), why should it care? If you want to delete something and it's already gone, then so what. The end result has still been achieved. This should not cause an exception, or there should at least be the option to ignore it and continue.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Apr 10, 2008 3:27 pm 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
For those who are interested, I'm now using this hack to NHibernate to prevent the problem:

In src\NHibernate\AdoNet\Expectations.cs, class BasicExpectation, method VerifyOutcomeNonBatched(), change

Code:
if (expectedRowCount > rowCount)
{
    throw new StaleStateException(...);
}


to

Code:
if (expectedRowCount > rowCount)
{
    if (statement.CommandText.ToUpperInvariant().StartsWith("DELETE "))
    {
        // Just ignore; who cares if the row to be deleted is already gone?
    }
    else
    {
        throw new StaleStateException(...);
    }
}


Unless someone can give a good reason why this is a bad idea, please consider this change for the trunk ...


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.