Here are some code mock ups of what I am dealing with:
Code:
<class name="PersonInfo" table="person_table">
<id name = "personId" column="person_id" type="long">
<generator class="native"/>
</id>
.....
<bag name="shots" inverse="true" cascade="save-update">
<key column="person_id"/>
<one-to-many class="Shot"/>
</bag>
</class>
The other mapping file looks like:
Code:
<class name="Shot" table="shot_table">
<composite-id>
<key-property name="personId" type="long" column="personId"/>
<key-property name="shotId" type="long" column="shot_id"/>
<key-property name="dateGiven" type="date" column="date_given"/>
</composite-id>
<version name="version" column="version" type="integer" unsaved-value="null"/>
....
</class>
The Shot class has the following equals and hashcode methods:
Code:
public boolean equals (Object obj) {
if (this == obj) return true;
if (!(obj instanceof Shot)) return false;
final Shot s = (Shot)obj;
EqualsBuilder eb = new EqualsBuilder();
eb.append(this.personId, s.getPersonId());
eb.append(this.shotId, s.getShotId());
eb.append(this.dateGiven, s.getDateGiven());
return eb.isEquals();
}
public int hashCode() {
if (this.personId == null) {
this.personId = new Long(0);
}
HashCodeBuilder hb = new HashCodeBuilder();
hb.append(this.personId);
hb.append(this.shotId);
hb.append(this.dateGiven);
return hb.hashCode(); // don't remember the actual method call
}
This is basically what I have. During the initial load of the PersonInfo object I would see updates being performed against the Shot collection. I thought maybe that was causing the version number in the object to become out of sync with the version number in the data base and that is why I set the flush mode to never. Since we did not flush the updates did not happen.
Now, there are other collections of objects in the PersonInfo object. We have special accesses in the application and those access rules are performed via named queries. So what we do is we load the PersonInfo object based on a person id. Then for the collections that have special access rules we set the collection to null and then do a query on that collection using the named query. The named query checks certain access privileges for the logged in user to determine what set of data to retrieve if any. This was performed via a view in the legacy system but we could use the view because it was using the special key word USER (Sybase) to determine the logged in user. In the new system we are using connection pooling so each user is not actually logged into the database.
So, we are making changes to the object perhaps that was causing the updates when the session was closed? And if so, that is fine accept it was during these updates that we initially saw the problem with this class and the version number.
The Shot collection does not have a named query that needs to be invoked or anything but I am now thinking that because we modify the other collections it causes an update but I still don't understand why we get a stale object exception for the Shot collection. For some records no error is reported and on others it will go through like the first 4 items of the Shot collection fine and then bomb on the 5 item with a stale object exception. I have looked at that 5th object and the personId, shotId and dateGiven are unique amongst the rows in the collection.
I am not at work today but the Exception says something to the effect that the object may have been modified/deleted by another transaction.
If we have to modify the table structure to add an identity column then that is what we will do. I have already tested this approach and it does not seem have any ill affect on the legacy system which must remain operational during the transition but since we do have other composite key tables I would like to know how to do this properly in Hibernate.
Any help will be greatly appreciated.