2009-04-16 13 views
7

Soy nuevo para hibernar, como verá pronto. Me disculpo si esta pregunta tiene una respuesta fácil, pero no estoy lo suficientemente familiarizado con toda la terminología para encontrarla fácilmente.Polimorfismo de hibernación: generación de instancias de la clase correcta

Digamos que tengo una clase base "A" y una subclase "B" que estoy mapeando con Hibernate, tal vez usando la tabla por estrategia de subclase. La clase base no es abstracta. Todos los Bs son As, pero no todos As son Bs. Esto se refleja en la base de datos, donde la tabla B hace referencia a la tabla A.

Bien, ahora supongamos que tengo un programa de algún tipo que muestra una lista de objetos A. El usuario puede seleccionar cualquier objeto A y ser llevado a una pantalla para modificarlo ... PERO, si el objeto A también es B, la pantalla permitirá al usuario modificar B en lugar de simplemente A.

Cómo el mundo ¿me acerco a esto?

Nota: No estoy preguntando sobre cómo determinar qué clase es un objeto. Lo que estoy preguntando es cómo puedo obtener hibernación para devolver una lista de objetos que son de la clase adecuada.

+0

¿Estás preguntando cómo hacer el mapeo de herencia? http://www.hibernate.org/hib_docs/v3/reference/en-US/html/inheritance.html ¿Puede ser más específico sobre la dificultad que tiene con la documentación? – erickson

+0

He leído un poco sobre el mapeo de herencia y reconocí la estrategia "tabla por subclase" como un posible ajuste. Lo que no entendí es que al consultar la superclase devolveré los objetos de la subclase ... de los cuales no encontré una muestra de código durante mi breve búsqueda de tiempo. ¡Muchas gracias! – Boden

Respuesta

6

Pido disculpas de nuevo por esta pregunta. Estoy muy sorprendido de cómo funciona la hibernación, es realmente genial. No pensé que haría todo esto automágicamente, y realmente ni siquiera estaba seguro de lo que estaba tratando de preguntar. Al responder a los comentarios, comencé a refinar la pregunta en mi cabeza y pude encontrar la respuesta que estaba buscando. Gracias a todos los que ayudaron.

La respuesta es: hibernate hace esto automáticamente.

Suponga que tiene en su base de datos de la tabla A con una clave primaria "id", y una mesa de B que tiene una clave principal llamado "A_ID" que hace referencia a la tabla A.

Así se crean las siguientes clases (abreviado):

public class A { 
    private String aProperty; 
    // ... getter and setter, etc 
{ 

public class B extends A { 
    private String bProperty; 
    // ... getter and setter, etc 
} 

Entonces mapearlos así:

<hibernate-mapping> 
    <class name="A" table="a" catalog="testokdelete"> 
     <id name="id" type="java.lang.Integer"> 
      <column name="id" /> 
      <generator class="identity" /> 
     </id> 
     <property name="aProperty" column="a_property"/> 
     <joined-subclass name="B" table="b"> 
      <key column="a_id"/> 
      <property name="bProperty" column="b_property"/> 
     </joined-subclass> 
    </class> 
</hibernate-mapping> 

y se puede devolver los objetos a y B mediante una consulta sencilla "de la a", como en el siguiente código:

Query query = session.createQuery("from A"); 
List<Object> objects = query.list(); 
for (Object object: objects) { 
    System.out.print("A property: "); 
    System.out.print(((A)object).getAProperty()); 
    System.out.print(", B property: "); 
    System.out.println((object.getClass() == B.class) ? ((B)object).getBProperty() : "not a B"); 
} 

único que hace es devolver una lista de objetos utilizando la consulta "de la A", y luego camina a través de ellos imprimir aProperty de nuestra clase y, si la clase es de tipo B, el bProperty de nuestra Clase B

La consulta de hibernación en este caso es automáticamente polimórfica y le dará un objeto B cuando corresponda.

+1

Sí, Hibernate hace esto. Pero usando (objeto.getClass() == B.class)? ((B) objeto) es RTTI. No debería tener que hacer esto, y hacerlo es indicativo de que sus clases están mal diseñadas. – tpdi

+0

Parece un código de depuración simple. No implica necesariamente que las clases "reales" se usarían de esta manera. Sin embargo, a veces se necesita RTTI, y en esos casos la expresión apropiada para la prueba es 'object instanceof B', not' object.getClass() == B.class'. – erickson

2

Puede usar RTTI, con instanceof, pero eso no está orientado a objetos.

su lugar, dar la clase base, A un método que pertenece a lo extra al B hace, por ejemplo, si es ACustomer y B es PreferredCustomer, el método podría ser isPreferredCustomer().

En A, el método devuelve falso, en B devuelve el turno.

Es importante tener en cuenta que no estamos preguntando si un objeto es de una cierta clase; estamos haciendo una pregunta comercial, preguntando a un objeto si puede hacer algo. Es una distinción sutil pero importante.

En particular, significa que su código siguiente no tendrá que cambiar cuando y si agrega más subclases Customer, siempre y cuando cada una de las categorías responda correctamente a la pregunta, isPreferredCustomer().

En su código:

if(a.isPreferredCustomer()) { 
    showPreferredCustomerPage(a) ; 
else { 
    show CustomerPage(a); 
} 

Se podría pensar que sea aún mejor para dar Customer un método showPage(), pero que se une demasiado firmemente sus modelos para sus puntos de vista.

En su lugar, coloque el código anterior en alguna clase de ViewDispatcher, que puede variar ortogonalmente con el Cliente y sus subclases.

Por ejemplo, puede tener varias subclases ViewDispatcher, algunas de las cuales se preocupan por PreferredCustomer sy otras que no.

+0

Buen punto para no meterse con los tipos en la lógica de los negocios; nunca antes se había pensado en eso. +1 –

+0

Pero en este caso A no sabe nada acerca de B. No hay propiedades de A, ni en la clase ni en la tabla que se está mapeando, que indican si A también es un B. – Boden

+1

Se debe establecer un punto de subclasificación capaz de agregar funcionalidad adicional a la clase sin tener que modificar la clase base. Esta solución enturbia a A con detalles de B. Lo que sucede cuando obtienes C que tiene un tipo de cliente diferente. Ahora necesita modificar isPreferredCustomer y no es booleano. – digitaljoel

1

Bien, bien, voy a suponer que tiene sus clases mapeadas correctamente. Si usted ha hecho esto, usted debe ser capaz de hacer lo siguiente, pienso:

public List<A> getAllClassA(){ 
     Session session = HibernateUtil.getSession(); 
     Criteria criteria = session.createCriteria(A.class); 

     List<A> ret = criteria.list(); 

     return ret; 
} 

si no están familiarizados con los criterios, es bastante fácil de aprender. Este fragmento de código recuperará todos los objetos de la clase A de la base de datos. Si lo trazas correctamente, creo que Hibernate también mantendrá los atributos B de tus objetos A si son en realidad objetos B (perdón si eso fue confuso).

Avíseme si este es el que está buscando o si necesita el código para HibernateUtil.

Cuestiones relacionadas