2008-09-01 9 views
5
@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
public class Problem { 
    @ManyToOne 
    private Person person; 
} 

@Entity 
@DiscriminatorValue("UP") 
public class UglyProblem extends Problem {} 

@Entity 
public class Person { 
    @OneToMany(mappedBy="person") 
    private List<UglyProblem> problems; 
} 

Creo que está bastante claro lo que intento hacer. Espero que la persona @ManyToOne sea heredada por la clase UglyProblem. Pero habrá una excepción que diga algo así como: "No se encontraron tales propiedades en la clase UglyProblem (mappedBy =" person ")".Por qué @OneToMany no funciona con herencia en Hibernate

Todo lo que encontré es this. No pude encontrar la publicación de Emmanuel Bernard explicando las razones detrás de esto.


Por desgracia, según la documentación de Hibernate "Propiedades de superclases no asignada como @MappedSuperclass se ignoran."

Bueno, yo creo que esto significa que si tengo estas dos clases:

public class A { 
    private int foo; 
} 

@Entity 
public class B extens A { 
} 

continuación campo foo no se asignarán a la clase B. Lo cual tiene sentido. Pero si tengo algo como esto:

@Entity 
public class Problem { 

@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
private Long id; 

private String name; 

public Long getId() { 
    return id; 
} 

public void setId(Long id) { 
    this.id = id; 
} 

public String getName() { 
    return name; 
} 

public void setName(String name) { 
    this.name = name; 
} 
} 

@Entity 
public class UglyProblem extends Problem { 

private int levelOfUgliness; 

public int getLevelOfUgliness() { 
    return levelOfUgliness; 
} 

public void setLevelOfUgliness(int levelOfUgliness) { 
    this.levelOfUgliness = levelOfUgliness; 
} 
} 

que esperar que el UglyProblem clase para tener campos campos id y name y ambas clases para ser mapeados usando una misma mesa. (De hecho, esto es exactamente lo que sucede, recién lo he comprobado). Tengo esta tabla:

CREATE TABLE "problem" (
    "DTYPE" varchar(31) NOT NULL, 
    "id" bigint(20) NOT NULL auto_increment, 
    "name" varchar(255) default NULL, 
    "levelOfUgliness" int(11) default NULL, 
    PRIMARY KEY ("id") 
) AUTO_INCREMENT=2; 

Volviendo a mi pregunta: ¿

espero @ManyToOne persona a ser heredada por clase UglyProblem.

Supongo que porque todos los demás campos asignados se heredan y no veo ninguna razón para hacer esta excepción para las relaciones ManyToOne.


Sí, lo vi. De hecho, utilicé la solución de solo lectura para mi caso. Pero mi pregunta fue "Por qué ..." :). Sé que hay una explicación dada por un miembro del equipo de hibernación. No pude encontrarlo y es por eso que pregunté.

Quiero conocer la motivación de esta decisión de diseño.

(si le interesó cómo he enfrentado este problema: heredé un proyecto creado usando hibernate 3. Era Jboss 4.0. Algo + hibernación ya estaba allí (lo descargarían todos juntos). Estaba moviendo este proyecto a Jboss 4.2.2 y descubrí que hay asignaciones de "@OneToMany mappedBy" heredados y funcionó muy bien en la configuración de edad ...)

+0

se debe añadir más detalles sobre su edición el 4 de septiembre.Especificar la lista en lugar de solo la Lista en el mapeo @OneToMany (mappedBy = "person") cambia la naturaleza del problema, ya que creo que previamente asumimos que deseaba asignar una Persona a una lista de Problemas (no Ugl –

Respuesta

4

Creo que es una sabia decisión tomada por el equipo de Hibernate. Podrían ser menos arrogantes y dejar en claro por qué se implementó de esta manera, pero así es como funcionan Emmanuel, Chris y Gavin. :)

Tratemos de entender el problema. Creo que tus conceptos son "mentirosos". Primero dice que muchos Problema s están asociados a Personas. Pero, entonces usted dice que uno Persona tiene muchos UglyProblem s (y no se relaciona con el otro Problema s). Algo está mal con ese diseño.

Imagine cómo se asignará a la base de datos. Tiene una única herencia de tablas, así que:

  _____________ 
      |__PROBLEMS__|   |__PEOPLE__| 
      |id <PK>  |   |   | 
      |person <FK> | -------->|   | 
      |problemType |   |_________ | 
      -------------- 

¿Cómo es la hibernación va a hacer cumplir la base de datos para hacer Problema sólo se refieren a personas si su problemtype es igual UP? Ese es un problema muy difícil de resolver. Entonces, si quieres este tipo de relación, cada subclase debe estar en su propia tabla. Eso es lo que hace @MappedSuperclass.

PS .: Lo siento por el dibujo feo: D

1

creo que se necesita para anotar el problema super-clase con @MappedSuperclass en lugar de @Entity.

4

Desafortunadamente, según Hibernate documentation "Las propiedades de las superclases no mapeadas como @MappedSuperclass se ignoran". Me encontré con esto también. Mi solución fue representar la herencia deseada a través de interfaces en lugar de los beans de la entidad.

En su caso, se podría definir lo siguiente:

public interface Problem { 
    public Person getPerson(); 
} 

public interface UglyProblem extends Problem { 
} 

A continuación, poner en práctica estas interfaces usando una superclase abstracta y dos subclases entidad:

@MappedSuperclass 
public abstract class AbstractProblemImpl implements Problem { 
    @ManyToOne 
    private Person person; 

    public Person getPerson() { 
     return person; 
    } 
} 

@Entity 
public class ProblemImpl extends AbstractProblemImpl implements Problem { 
} 

@Entity 
public class UglyProblemImpl extends AbstractProblemImpl implements UglyProblem { 
} 

Como beneficio adicional, si el código usando las interfaces en lugar de los beans de entidad reales que implementan esas interfaces, hace que sea más fácil cambiar las asignaciones subyacentes más adelante (menos riesgo de romper la compatibilidad).

0

me di cuenta de cómo hacer el problema OneToMany mappedBy.

En la clase derivada UglyProblem de la publicación original. El método de devolución de llamada debe estar en la clase derivada, no en la clase principal.

@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@ForceDiscriminator 
public class Problem { 

} 

@Entity 
@DiscriminatorValue("UP") 
public class UglyProblem extends Problem { 
    @ManyToOne 
    private Person person; 
} 

@Entity 
public class Person { 
    @OneToMany(mappedBy="person") 
    private List<UglyProblem> problems; 
} 

Encontré la salsa secreta para usar al menos Hibernate. http://docs.jboss.org/hibernate/stable/annotations/api/org/hibernate/annotations/ForceDiscriminator.html El @ForceDiscriminator hace que @OneToMany honre al discriminador

Requiere anotaciones de Hibernate.

5

En mi caso, quería utilizar el tipo de herencia SINGLE_TABLE, por lo que usar @MappedSuperclass no era una opción.

Lo que funciona, aunque no muy limpio, es añadir la propia cláusula de Hibernate @Where a la asociación @OneToMany para forzar el tipo de consultas:

@OneToMany(mappedBy="person") 
@Where(clause="DTYPE='UP'") 
private List<UglyProblem> problems; 
+0

Alternativas a ' @ Where' para eclipseLink o JPA en general sería muy apreciado – Odys

+0

Hola Odys, en EclipseLink simplemente no necesitas especificar nada. Hibernate normalmente te obliga a especificar en la anotación oneToMany la targetEntity = Person.class. Así que cuando tengas Entidad con campo1. UglyPerson uglyPerson; y campo2 BeutifulPerfoson beutifulPerson; en eclipselink, automáticamente sabe que debe mirar su BeuftifulPerson @DescriminatorValue ("PRETTY_PERSON") y buscar el material correcto. Hibernate no lo sabe y le obliga a usar el @ Cláusula WHERE. Eclipselink se siente mal analizando una jerarquía de clases y resolviendo el mapeo de eToMany – 99Sono

+0

En Ecliipselink solo asegúrese de que sus entidades que son parte de una jerarquía de clases tienen cada una su propia; @DiscriminatorValue ("BEAUTIFUL_PERON") descriminator y añadir a la clase base si su entidad algo como: @DiscriminatorColumn (name = "ENTITY_CLASS", descriminatorType = cadena) y se puede utilizar fácilmente @Inheritance (SINGLE_TABLE) con Hibernate, está bastante atascado en esto, ya que necesita especificar un WHERE clasuse, y mantener continuamente el predicado con el ENTITY_CLASS para cada elemento secundario en la jerarquía. Así que aquí eclipselink está muy por delante. – 99Sono

Cuestiones relacionadas