Yes, I know, composite ids are out of favor here, however we have strong design reasons to use composite ids, so we do.
Now we stuck with a hibernate error, and the behavior we are observing looks like a bug.
We have a root class
R and its subclass
S on a single table inheritance.
R has fields
OID and
CID as the primary key,
CID is also used as discriminator column.
R has collection of classes
L, which have two Many-To-One association to
R -
left and
right. Instances of
L we use to model attributed Many-Many-To-Many association
R<->
R.
In our basic test we managed to create new and get existing instances of
R and
S.
We also succeeded with creating an association
L between a new instance of
R and an existing instance of
R.
However, on creating association
new R <->
existing S, we are getting error:
Code:
org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.entity.L.right -> com.entity.R
We have debugged hibernate and found that exception is thrown in
CascadingAction.java:~353 because
ForeignKeys.isTransient returns
true. This happens because in
AbstractEntityPersister.java:~3305 function
canExtractIdOutOfEntity() returns
false.
We found what is the difference between runs
R<->
R and
R<->
S: for the first case
hasIdentifierMapper() (
AbstractEntityPersister.java:~3410) returns
true, while for the second –
false.
In the debugger, we have changed
hasIdentifierMapper for class
S to
true and test has succeeded and was working well until we redeploy our application.
We have debugged further and found that this property (
hasIdentifierMapper) is set from value got from the Metamodel (
PersistentClass:~758)
Code:
public boolean hasIdentifierMapper() {
return identifierMapper != null;
}
In our opinion, this method should be overridden in
Subclass (or
SingleTableSubclass) as the following:
Code:
public boolean hasIdentifierMapper() {
return superclass.hasIdentifierMapper();
}
What we need is a quick workaround which does not require changes in hibernate sources.
Setting
AbstractEntityPersister.hasIdentifierMapper to
true would work for us, unfortunately we do not know how to get access to the instance of
AbstractEntityPersister corresponding to our class (
S) and what is proper context of doing this fix.
Thank you for reading to this point ;)