Hibernate version: 3.3.1GA
Mapping documents:
Code:
@Entity
public class DefaultInstrument implements Instrument {
@Column(length = 6, nullable = false)
String groupCode;
@NaturalId(mutable = false)
@Column(length = 6, updatable = false, nullable = false)
String productCode;
// This is nullable because this value is NOT required for order entry.
@Column(length = 20)
String securityDescription;
@Id
@GeneratedValue
long id;
@Column(length = 12, nullable = false)
long securityId;
/** getters/setters **/
}
Code between sessionFactory.openSession() and session.close(): This is a bit complicated and spread through a few classes.
getHibernateTemplate().saveOrUpdate(updateData); is the final call made, I'm using Spring 2.5 so I go through a Hibernate Template, this manages sessions and JDBC connections for me, the applications ORM is simple and only contains this one Insturment object for now.
What I'm doing is creating an Instrument object with productCode (naturalId) and all other fields except ID populated then passing it to my DAO which calls saveOrUpdate. This object is properly assigned an id of 1. I then receive another Instrument object with the same naturalId but possibly different values for non-key fields. This is a transient object which I also send to my DAO through saveOrUpdate. Here is my issue, saveOrUpdate looks at the id (null/0) and decides this object needs to be save'd not updated. So I looked around and was told the proper way to implement this is via an Interceptor and overriding the isTransient() method.
So I did this and inside the function I call the following:
Code:
if(entity instanceof Instrument) {
Instrument tempInstrument = (Instrument)entity;
Instrument fromDB = instrumentDataStore.load(tempInstrument);
if(fromDB != null) {
tempInstrument.setId(fromDB.getId());
return false;
}
}
return super.isTransient(entity);
Now at first I tried this without setting the ID but it didn't work, Hibernate still went and did a snapshot search based on the null/0 ID instead of the Natural ID if all I did was return false after testing that the natural ID exists.
Am I approaching this situation the wrong way or does this seem correct? I'm currently writing a unit test for a simplified example of my issue but more importantly I'm concerned that I broke hibernate by setting this id myself. For example I'm not sure if what I'm doing causes two instances to represent the same row (same id) within one Unit of Work, if this is what I did how much of an issue is it?
I'm thinking I can keep a set of these object myself (thus only the newest version survives) and then batchSave or something all of them at the end, this makes my architecture bottleneck (potentially) if not I have to design to prevent bottle necks and I rather like being able to just receive an Instrument and send it off to my DAO service without any concern.
Full stack trace of any exception that occurs: N/A
Name and version of the database you are using:
Derby 10.4
The generated SQL (show_sql=true):
This is in my example above.
Debug level Hibernate log excerpt:
This is also in my example above.
Ideas, questions?
Thanks.
I'll post a Unit Test to clarify the situation when I'm done with it.