Reputation: 747
I'm using hibernate 3.6.3.Final. I have two relational entities A & B with a unidirectional ManyToOne defined as:
@Entity public class A {
...
@Version @Column ( name = "ChangeNumber" )
public Long getVersion() { return version; }
@ManyToOne @JoinColumn( name = "B_ID" )
public B getRelationalB() { return relationalB; }
...
}
@Entity public class B {
@Version @Column ( name = "ChangeNumber" )
public Long getVersion() { return version; }
....
}
Now suppose I have a B instance persistent in db already with pk id = 1, then doing the following operation:
A a = new A();
a.setRelationalB( new B( 1 ) );
session.saveOrUpdate( a ) ;
throws an the famous "TransientObjectException: object references an unsaved transient..." exception.
Surprisingly enough, if @Version @Column is removed or made @Transient, the above code would work perfectly fine.
Any idea why i'm observing this behavior?
Upvotes: 1
Views: 730
Reputation: 322
I had "object references an unsaved transient..." exception a lot after adding the @Version column, too. Here's how I solved it in my case:
In my scenario the problem was on the foreign keys. The code was written so that instead of loading the referred object it was creating a new instance and setting the primary key hoping that Hibernate would be able to find the real one. I repeat: it worked fine before the @Version thing.
Illustrating:
Consider an object of class B
with id 1
exists on the database and now we're saving a new instance of A
.
previously (no good) (was giving exception after @Version added):
a.setB(new B(1));
sf.getCurrentSession().save(a);
fixed (working well) - using @Version with no problems:
a.setB((B) sf.getCurrentSession().get(B.class, 1));
sf.getCurrentSession().save(a);
When debugging Hibernate I find out it does some extra checking when the @Version column is present.
So, I believe people having this error either aren't loading objects they're trying to make reference to (which is a better practice anyway) or they're really trying to save a new instance of B
(for example) but didn't configure cascade save for it.
Upvotes: 0
Reputation: 29897
The problem is that you're not using the entity B which is in the database
A a = new A();
// you're instantiating a "new" B with id 1, this is not the same
// as the "object" you have in the database.
a.setRelationalB( new B( 1 ) );
session.saveOrUpdate( a ) ;
The problem is that hibernate cannot recognize that the new B you created is the same one as the one stored on the db. If you want to know the reason behind this, read about the Unit of Work pattern.
try doing something like
B b = sessions.get(B.class, 1)
A a = new A();
a.setRelationalB( b );
session.saveOrUpdate( a ) ;
On another point: if you want to save the new instances of both objects in one go, then you'll need to do a cascade.
Upvotes: 1