Hibernate version: 2.1.8
I have a simple Parent/Child relationship, single collection from parent to child, and single association back from the child to the parent. All other properties on both objects are simple. Both objects are versioned using a version number. The parent side of the collection (i.e. the set) is marked as inverse = true.
I'm using a think client with disconnected objects, so I select the parent/child object tree in one session and update in another. The update method I have takes a single parameter, the parent object.
By using saveOrUpdateCopy, hibernate get's the previous state from the database (or 2nd level cache) so that it can determine what to update.
Here's the scenario, I get the parent object, and assuming I make no changes, send the object back for updating.
If the child collection isn't loaded then no updates occur. This is the behaviour I expect.
If the child collection is loaded then the parent object has it's version number updated. This is not what I'd expect.
Debugging I've found that the cause of this is the copy of the child collection. After retrieving the persistent instance from the session it tries to copy the new values over the retrieved values. The collection becomes marked dirty. Then later, when (in SessionImpl.isUpdateNecessary) is tries to determine if the parent instance is dirty, using the DirtyCollectionSearchVisitor, it sees the 'dirty' collection and deems the instance as dirty.
In this instance I don't beleive the collection should be dirty, but even if it was, because the parent side of the association is inverse=true, the parent should not be affected by the change to the collection; the child is managing the association.
I have applied a fix to the 2.1.8 code that cures my problem. In DirtyCollectionSearchVisitor.processCollection(...), inside the if(session.collectionIsDirty(coll) ) { ... } I have added a check for whether the association is inverse, and to only mark the instance as dirty if the association isn't :
Code:
if ( session.collectionIsDirty(coll) ) {
boolean inverse = session.isInverseCollection( coll );
// Only dirty if the collection mapping isn't inverse
if( !inverse ) {
dirty=true;
return null; //NOTE: EARLY EXIT!
}
}
With this fix (with the child collection loaded in the parent instance) :
* No changes mean no updates
* A change to the parent instance means a single update to the parent table
* A change to a single child instance means a single update to the child table
* A new child object means a single insert into the child table
* An update to the parent instance and a single child instance means two updates (one to parent, one to child)
... all as I would expect it to behave.
I think this is a bug rather than a feature and if it is I'll gladly raise the bug in JIRA with the small sample I have.
Are there any obvious (or less obvious) side effects of this? So far I've not seen any.