I have found a problem using outer join, in last Hibernate version it is too.
I have two class hierarchies
1. superclass B and two of it's subclasses B1 and B2.
2. superclass A and two of it's subclasses A1 and A2 which have a reference to B1 and B2 class instance respectively
The problem becomes apparent when I add attribute outer-join="true" to both A1 and A2 subclasses mappings for "many-to-one" mapping type.
Both objects A1, A2 and referenced objects B1 and B2 saved to the database ok, but reading B2 object referenced by A2 returns reference to B1!!! Discriminator values are unique and I see that deleting mapping for B1 (which goes first) lets me read object B2 with no problem. It's obviously that discriminator value in this case is not used. So I remove outer-join attribute and all works just fine, but I loose performance. How to deal?
Mapping documents:
A mappings:
Code:
<hibernate-mapping>
<class name="A"
table="a">
<id name="id"
column="a_id"
type="long"
unsaved-value="null"
access="field">
<generator class="native"/>
</id>
<discriminator column="discriminator"
type="string"
length="2"/>
<subclass name="A1"
discriminator-value="A1">
<many-to-one name="b"
class="B1"
column="b_id"
cascade="save-update"
outer-join="true"
foreign-key="fk_a_id"/>
</subclass>
<subclass name="A2"
discriminator-value="A2">
<many-to-one name="b"
class="B2"
column="b_id"
cascade="save-update"
outer-join="true"
foreign-key="fk_a_id"/>
</subclass>
</class>
</hibernate-mapping>
B mappings:
Code:
<hibernate-mapping>
<class name="B"
table="b">
<id name="id"
column="b_id"
type="long"
unsaved-value="null"
access="field">
<generator class="native"/>
</id>
<discriminator column="discriminator"
type="string"
length="2"/>
<subclass name="B1"
discriminator-value="B1"/>
<subclass name="B2"
discriminator-value="B2"/>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
...
// first succeedes
check(sessionFactory, new A1(new B1()));
// second fails!!!
check(sessionFactory, new A2(new B2()));
...
private static void check(SessionFactory sessionFactory, A a) {
// save
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
session.saveOrUpdate(a);
transaction.commit();
session.close();
System.out.println(a);
// read
session = sessionFactory.openSession();
A aa = (A) session.get(A.class, a.getId());
System.out.println(aa);
session.close();
}
Full stack trace of any exception that occurs:Code:
[java] org.hibernate.PropertyAccessException: Exception occurred inside setter of A2.b
[java] at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:180)
[java] at org.apache.tools.ant.taskdefs.Java.run(Java.java:710)
[java] at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:178)
[java] at org.apache.tools.ant.taskdefs.Java.execute(Java.java:84)
[java] at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:275)
[java] at org.apache.tools.ant.Task.perform(Task.java:364)
[java] at org.apache.tools.ant.Target.execute(Target.java:341)
[java] at org.apache.tools.ant.Target.performTasks(Target.java:369)
[java] at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1216)
[java] at org.apache.tools.ant.Project.executeTarget(Project.java:1185)
[java] at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:40)
[java] at org.apache.tools.ant.Project.executeTargets(Project.java:1068)
[java] at org.apache.tools.ant.Main.runBuild(Main.java:668)
[java] at org.apache.tools.ant.Main.startAnt(Main.java:187)
[java] at org.apache.tools.ant.launch.Launcher.run(Launcher.java:246)
[java] at org.apache.tools.ant.launch.Launcher.main(Launcher.java:67)
[java] Caused by: org.hibernate.PropertyAccessException: Exception occurred inside setter of A2.b
[java] at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:65)
[java] at org.hibernate.tuple.AbstractEntityTuplizer.setPropertyValues(AbstractEntityTuplizer.java:330)
[java] at org.hibernate.tuple.PojoEntityTuplizer.setPropertyValues(PojoEntityTuplizer.java:188)
[java] at org.hibernate.persister.entity.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:3232)
[java] at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:126)
[java] at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:842)
[java] at org.hibernate.loader.Loader.doQuery(Loader.java:717)
[java] at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224)
[java] at org.hibernate.loader.Loader.loadEntity(Loader.java:1785)
[java] at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:93)
[java] at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:81)
[java] at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:2730)
[java] at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:365)
[java] at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:346)
[java] at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:123)
[java] at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:177)
[java] at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:87)
[java] at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:869)
[java] at org.hibernate.impl.SessionImpl.get(SessionImpl.java:806)
[java] at org.hibernate.impl.SessionImpl.get(SessionImpl.java:799)
[java] at Test.check(Test.java:39)
[java] at Test.main(Test.java:22)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
[java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
[java] at java.lang.reflect.Method.invoke(Unknown Source)
[java] at org.apache.tools.ant.taskdefs.ExecuteJava.run(ExecuteJava.java:202)
[java] at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:134)
[java] ... 15 more
[java] Caused by: java.lang.reflect.InvocationTargetException
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
[java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
[java] at java.lang.reflect.Method.invoke(Unknown Source)
[java] at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:42)
[java] ... 42 more
[java] Caused by: java.lang.IllegalArgumentException: B1
[java] at A2.setB(A2.java:13)
[java] ... 47 more
[java] --- Nested Exception ---
[java] org.hibernate.PropertyAccessException: Exception occurred inside setter of A2.b
[java] at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:65)
[java] at org.hibernate.tuple.AbstractEntityTuplizer.setPropertyValues(AbstractEntityTuplizer.java:330)
[java] at org.hibernate.tuple.PojoEntityTuplizer.setPropertyValues(PojoEntityTuplizer.java:188)
[java] at org.hibernate.persister.entity.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:3232)
[java] at org.hibernate.engine.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:126)
[java] at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:842)
[java] at org.hibernate.loader.Loader.doQuery(Loader.java:717)
[java] at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224)
[java] at org.hibernate.loader.Loader.loadEntity(Loader.java:1785)
[java] at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:93)
[java] at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:81)
[java] at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:2730)
[java] at org.hibernate.event.def.DefaultLoadEventListener.loadFromDatasource(DefaultLoadEventListener.java:365)
[java] at org.hibernate.event.def.DefaultLoadEventListener.doLoad(DefaultLoadEventListener.java:346)
[java] at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:123)
[java] at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:177)
[java] at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:87)
[java] at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:869)
[java] at org.hibernate.impl.SessionImpl.get(SessionImpl.java:806)
[java] at org.hibernate.impl.SessionImpl.get(SessionImpl.java:799)
[java] at Test.check(Test.java:39)
[java] at Test.main(Test.java:22)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
[java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
[java] at java.lang.reflect.Method.invoke(Unknown Source)
[java] at org.apache.tools.ant.taskdefs.ExecuteJava.run(ExecuteJava.java:202)
[java] at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:134)
[java] at org.apache.tools.ant.taskdefs.Java.run(Java.java:710)
[java] at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:178)
[java] at org.apache.tools.ant.taskdefs.Java.execute(Java.java:84)
[java] at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:275)
[java] at org.apache.tools.ant.Task.perform(Task.java:364)
[java] at org.apache.tools.ant.Target.execute(Target.java:341)
[java] at org.apache.tools.ant.Target.performTasks(Target.java:369)
[java] at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1216)
[java] at org.apache.tools.ant.Project.executeTarget(Project.java:1185)
[java] at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:40)
[java] at org.apache.tools.ant.Project.executeTargets(Project.java:1068)
[java] at org.apache.tools.ant.Main.runBuild(Main.java:668)
[java] at org.apache.tools.ant.Main.startAnt(Main.java:187)
[java] at org.apache.tools.ant.launch.Launcher.run(Launcher.java:246)
[java] at org.apache.tools.ant.launch.Launcher.main(Launcher.java:67)
[java] Caused by: java.lang.reflect.InvocationTargetException
[java] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java] at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
[java] at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
[java] at java.lang.reflect.Method.invoke(Unknown Source)
[java] at org.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:42)
[java] ... 42 more
[java] Caused by: java.lang.IllegalArgumentException: B1
[java] at A2.setB(A2.java:13)
[java] ... 47 more
Name and version of the database you are using:Code:
MySQL 4
The generated SQL (show_sql=true):Code:
insert into b (discriminator) values ('B1')
insert into a (b_id, discriminator) values (?, 'A1')
select a0_.a_id as a1_0_1_, a0_.b_id as b3_0_1_, a0_.discriminator as discrimi2_0_1_, b1x1_.b_id as b1_1_0_ from a a0_ left outer join b b1x1_ on a0_.b_id=b1x1_.b_id where a0_.a_id=?
insert into b (discriminator) values ('B2')
insert into a (b_id, discriminator) values (?, 'A2')
select a0_.a_id as a1_0_1_, a0_.b_id as b3_0_1_, a0_.discriminator as discrimi2_0_1_, b1x1_.b_id as b1_1_0_ from a a0_ left outer join b b1x1_ on a0_.b_id=b1x1_.b_id where a0_.a_id=?
Debug level Hibernate log excerpt:Code:
DEBUG