2009-06-11 13 views
10

Esta es una pregunta sobre el polimorfismo Hibnerate y una pregunta sobre el diseño del modelo de datos ; ellos están entrelazados. He usado Hibernate en el pasado, y lo he disfrutado, pero a veces me resulta difícil pensar en sobre cualquier cosa que no sean diseños triviales. No es un golpe en Hibernate; solo una observación de que el ORM en general puede ser un desafío.Polimorfismo Hibernate

Creo que esta es una pregunta de Hibernate 101, pero no estoy seguro. Lo que trato de lograr ni siquiera es posible.

Tengo una fruta de clase abstracta que se subclasificará en Apple y naranja. Tengo una clase Note que representa notas o comentarios sobre manzanas y naranjas. Una manzana o naranja puede tener muchas notas asociadas, pero solo una manzana o naranja será alguna vez asociada a una nota determinada.

Aquí hay bocetos de las clases, donde estoy omitiendo donde van las identificaciones del objeto y las propiedades de las manzanas que las distinguen de las naranjas . Por el momento, no estoy muy convencido de cuál es la estrategia de herencia de Hibernate que uso.

abstract public class Fruit { 
} 

// Apples have notes written about them: 
public class Apple extends Fruit { 
    private Set<Note> note; 
    ... 

    @OneToMany(cascade = CascadeType.ALL) 
    public Set<Note> getNote() { 
     return note; 
    } 
} 


// Oranges have notes written about them: 
public class Orange extends Fruit { 
    private Set<Note> note; 
    ... 

    @OneToMany(cascade = CascadeType.ALL) 
    public Set<Note> getNote() { 
     return note; 
    } 
} 

Aquí es la clase Nota implementado actualmente, en donde vemos que que tiene campos para tanto una manzana y una naranja. La falla o inelegancia en este diseño es que una instancia única de nota solo apuntará a una de Apple o Naranja, y nunca ambas. Por lo tanto, si una nota está vinculada a una manzana, el campo naranja es superfluo y antiestético, y viceversa.

// A note about an Apple or Orange 
public class Note { 
    private String theNote; 
    private Apple apple; 
    private Orange orange; 
    ... 

    // with the usual many to one mapping 
    @ManyToOne 
    @JoinColumn(name = "apple_id") 
    public Apple getApple() { 
     return apple; 
    } 

    // with the usual many to one mapping 
    @ManyToOne 
    @JoinColumn(name = "orange_id") 
    public Orange getOrange() { 
     return orange; 
    } 

    ... 
} 

Sin embargo, esta es la clase de nota que yo creo quiero basar mi diseño , pero no estoy seguro de cómo pensar en esto con respecto a Hibernate mapeo anotación y tabla:

// A note about a fruit: 
public class Note { 
    private String theNote; 
    private Fruit fruit; 
    ... 
} 

donde la fruta será una instancia de Apple o naranja.

¿Puede esta última clase de Nota, con su referencia a una Fruta, que realmente tendrá una Manzana o Naranja, incluso conciliarse con el mapeo ORM de Hibernate? Si es así, ¿alguien puede hablar sobre cómo?

+0

Tengo un problema similar debido a que mi código se ejecuta en una base de datos MySQL. ¿Estás dispuesto a ayudarme con mi pregunta relacionada? Aquí está el enlace: http://stackoverflow.com/questions/25252541/generatedvalue-for-a-java-abstract-superclass-over-mysql – CodeMed

Respuesta

13

Esto es absolutamente posible. Se podría asociar las notas con la clase abstracta Fruit en lugar de repetir en cada una de las implementaciones:

@Entity 
@Inheritance 
public abstract class Fruit { 
    private Set<Note> notes; 
    ... 

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "fruit") 
    public Set<Note> getNotes() { 
     return notes; 
    } 
} 

@Entity 
public class Apple extends Fruit { 
    ... 
} 


@Entity 
public class Orange extends Fruit { 
    ... 
} 

@Entity 
public class Note { 
    private String theNote; 

    @ManyToOne 
    private Fruit fruit; 
    ... 
} 

et voilà!

- Adición basada en el comentario: JPA proporciona múltiples estrategias para lidiar con la herencia. El relevant section in the Java EE tutorial debería ayudarlo a comenzar.

Básicamente, las opciones son:

  • almacenar todo en una mesa y el uso de una columna de discriminador saber qué fila es el tipo
  • almacenar cada clase concreta (Apple y naranja) en una tabla separada
  • Tener una mesa común de la fruta con una columna de discriminador, y las tablas manzana y naranja con una clave externa a la tabla de frutas

Otra edición: Notamos que esta es una pregunta de Hibernate, no de JPA. Sin embargo, no hace demasiada diferencia, ya que las opciones son las mismas. Aquí está el relevant section in the Hibernate docs.

+0

Temporal -1: esto no responde la pregunta, ¿o sí? Le has contado a Hibernate sobre la relación entre Fruit y Note. ¿Cómo le dices cómo desambiguar una fruta para una manzana o una naranja? –

+1

@ Jason: En realidad, sí, y muy literalmente. Si vuelves a leer la pregunta, particularmente los últimos párrafos a partir del segundo bloque de código, el código que estoy proporcionando es exactamente lo que pide ae6rt. – Henning

+0

-1 eliminado ... ¿podría explicarnos cómo se almacena una manzana en la base de datos de forma diferente a una naranja? –

4

Este patrón es muy común en las capas de datos basadas en Hibernate. La forma en que funciona internamente se basa en gran medida en la estrategia de herencia que se utiliza.

Al usar la tabla por clase o tabla por herencia de subclase, se creará una tabla para cada subclase/clase. Por ejemplo, en su caso, tendría una tabla Fruit y dos tablas Apple y Orange, con referencias de clave externa entre Fruit y Apple/Orange. Al solicitar una sola fruta (ya sea de manzana o naranja) por ID, Hibernate se unirá a la mesa de frutas con la tabla de naranja y manzana. Cada fila se transformará en una manzana o naranja dependiendo de la tabla en la que se recuperaron los campos.

Otra posibilidad es utilizar discriminadores. Se utilizará una sola tabla Fruit que contendrá un campo discriminador (por ejemplo, fruit_type tomando los valores apple y orange). Dependiendo del valor de este campo, Hibernate determinará si el objeto correspondiente es un Apple o un Orange.

En su caso, en el caso de carga ansiosa, cuando Hibernate carga el objeto Note, buscará con entusiasmo la fruta correspondiente y rellenará el campo de fruta con una instancia de Apple o Orange en consecuencia.

En el caso de la recuperación diferida, el campo de la fruta será un proxy que implementa la interfaz de Fruit. Hasta que se cargue el campo de fruta real, su tipo es indeterminado.

Espero que responda algunas de sus consultas.