Hi feh
I've implemented your example scenario using table-per-subclass to create a separate table for A, B and C.
I couldn't get this working using the D interface alone - added an abstract class 'DImpl' that implements D and is extended by concrete classes B and C. There are private (hibernate only) get/set methods for the DImpl in A and public get/set methods for DReference.
The test case creates 2 instances of A in the database - one with A as the DRef, one with B as the DRef. When the A's are re-loaded from the DB I print the class names of the DRef. As expected they are A and B;)
My HibernateUtil is configured to use hsqldb.
Mike
class A
Code:
package test.feh;
public class A {
private Long id;
private DImpl dImpl;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public D getDReference() {
return dImpl;
}
public void setDReference(D dReference) {
if (!(dReference instanceof DImpl)) {
throw new IllegalArgumentException("DReference must be an instance of class DImpl");
}
dReference = (DImpl)dReference;
}
@SuppressWarnings("unused")
private DImpl getDImpl() {
return dImpl;
}
@SuppressWarnings("unused")
private void setDImpl(DImpl impl) {
dImpl = impl;
}
}
class B
Code:
package test.feh;
public class B extends DImpl {
}
class C
Code:
package test.feh;
public class C extends DImpl {
}
interface D
Code:
package test.feh;
public interface D {
}
abstract class DImpl
Code:
package test.feh;
public abstract class DImpl implements D {
private Long id;
private A aReference;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public A getAReference() {
return aReference;
}
public void setAReference(A reference) {
aReference = reference;
}
}
class HibernateUtil
Code:
package test.feh;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static SessionFactory factory;
static {
Configuration config = new Configuration()
.addClass(A.class)
.addClass(DImpl.class)
.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect")
.setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver")
.setProperty("hibernate.connection.url", "jdbc:hsqldb:mem:test")
.setProperty("hibernate.connection.username", "sa")
.setProperty("hibernate.connection.password", "")
.setProperty("hibernate.hbm2ddl.auto", "create-drop")
.setProperty("hibernate.cache.provider_class", "org.hibernate.cache.NoCacheProvider")
.setProperty("hibernate.show_sql", "true");
HibernateUtil.setSessionFactory(config.buildSessionFactory());
}
public static synchronized Session getSession() {
if (factory == null) {
factory = new Configuration().configure().buildSessionFactory();
}
return factory.openSession();
}
public static void setSessionFactory(SessionFactory factory) {
HibernateUtil.factory = factory;
}
}
class TestIt
Code:
package test.feh;
import junit.framework.TestCase;
import org.hibernate.Hibernate;
import org.hibernate.Session;
public class TestIt extends TestCase {
public void testLoad() {
Long aWithBId = createDatabaseObjects(new B());
Long aWithCId = createDatabaseObjects(new C());
Session session = HibernateUtil.getSession();
A aWithB = (A)session.load(A.class, aWithBId);
A aWithC = (A)session.load(A.class, aWithCId);
Hibernate.initialize(aWithB);
Hibernate.initialize(aWithC);
session.close();
System.out.println("A with B - DReference class = "+aWithB.getDReference().getClass());
System.out.println("A->B->A.id: "+aWithB.getDReference().getAReference().getId());
System.out.println("A with C - DReference class = "+aWithC.getDReference().getClass());
System.out.println("A->C->A.id: "+aWithC.getDReference().getAReference().getId());
}
private Long createDatabaseObjects(D d) {
Session session = HibernateUtil.getSession();
session.beginTransaction();
session.save(d);
A a = new A();
a.setDReference(d);
Long aId = (Long)session.save(a);
session.getTransaction().commit();
session.close();
return aId;
}
}
Mapping File A.hbm.xml
Code:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="test.feh">
<class name="A" table="a_table">
<id name="id" column="id">
<generator class="increment"/>
</id>
<one-to-one name="DImpl"/>
</class>
</hibernate-mapping>
Mapping File DImpl.hbm.xml
Code:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="test.feh">
<class name="DImpl" table="d_table">
<id name="id" column="id">
<generator class="native"/>
</id>
<one-to-one name="AReference"/>
<joined-subclass name="B" table="b_table">
<key column="id"/>
</joined-subclass>
<joined-subclass name="C" table="c_table">
<key column="id"/>
</joined-subclass>
</class>
</hibernate-mapping>