Hello everyone,
I'm using Hibernate 3.1. I have a recurrent problem, albeit maybe quite simple, about retrieval of subclassed entities.
I'll explain using a clean example: Suppose I have four classes --
ClassA,
ClassB,
ClassC, and
ClassCChild, where the latter is a subclass of
ClassC.
ClassA has a property of type
ClassB, which in turn has a property of type
ClassC (both are mapped via "many-to-one" relationships):
Code:
public class ClassA {
private ClassB classB;
// getter/setter follows...
}
public class ClassB {
private ClassC classC;
// getter/setter follows...
}
Mapping looks like:
Code:
<class name="ClassA" ...>
...
<many-to-one
name="classB"
class="ClassB"
column="IDCLASSB"/>
</class>
...and similar to
ClassB.classC. The
ClassCChild inheritance is represented by the "Table per Hierarchy" model, thus having a discriminator value.
Now let me load an instance of
ClassA and obtain the referred
ClassC instance:
Code:
ClassA classA = (ClassA) session.get(ClassA.class, new Integer(1));
ClassC classC = classA.getClassB().getClassC();
According to data in my database,
classC should hold a
ClassCChild instance. This is in fact evidenced by calling
Hibernate.getClass():
Code:
System.out.println(Hibernate.getClass(classA.getClassB().getClassC()));
// returns "class ClassCChild", as expected
However, I can't typecast
classC to
ClassCChild:
Code:
ClassCChild child = (ClassCChild) classC;
// yelds a java.lang.ClassCastException exception
I understand that this is an issue of how CGLIB handles proxied objects -- when I
get() a
ClassA instance, it's impossible to know in advance what is the type of
classA.getClassB().getClassC(), so it's mapped to a general
ClassC proxy. But, what to do now? The only solution that I found so far is to ask explicitely for the
ClassCChild instance...
Code:
ClassCChild child = (ClassCChild) session.get(ClassCChild.class, classC.getId());
...which I find to be rather ugly, since Hibernate+CGLIB should (and have enough information to) give me an instance of the correct class. (Anyway,
classA.getClassB().getClassC() will always point to a "pure"
ClassC instance or proxy.) Or I could issue a "deep-outer-join-query" to avoid proxies and obtain the correct class from the beginning -- but this isn't good for me, since I have a quite "fat" database (both in rows and in columns) and I want to retrieve data only when it's strictly necessary.
Now, can anyone give me a hint?