tutorial mvc mediante libro framework español ejemplos desarrollo books aplicaciones java hibernate inheritance orm

java - mvc - Por qué @OneToMany no funciona con herencia en Hibernate



spring java tutorial (5)

Creo que debe anotar su superclase de problema con @MappedSuperclass en lugar de @Entity .

@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 estoy tratando de 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 ")".

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

Desafortunadamente, según la documentación de Hibernate, se ignoran las propiedades de las superclases no asignadas como @MappedSuperclass.

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

public class A { private int foo; } @Entity public class B extens A { }

entonces el campo foo no se mapeará para 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; } }

Espero que la clase UglyProblem tenga fileds id y name y que ambas clases se mapeen utilizando la misma tabla. (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 que la persona @ManyToOne sea heredada por la clase UglyProblem.

Lo espero 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 descubrir la motivación de esta decisión de diseño.

(si le interesó cómo me he enfrentado a este problema: heredé un proyecto creado utilizando hibernate 3. Era Jboss 4.0. algo + hibernación ya estaba allí (lo descargaría todo junto). Estaba trasladando este proyecto a Jboss 4.2. 2 y descubrí que hay asignaciones heredadas de "@OneToMany mappedBy" y funcionó bien en la configuración anterior ...)


Desafortunadamente, según la documentación de Hibernate, se ignoran las propiedades de las superclases no asignadas como @MappedSuperclass. 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, podría definir lo siguiente:

public interface Problem { public Person getPerson(); } public interface UglyProblem extends Problem { }

Luego implemente estas interfaces usando una superclase abstracta y dos subclases de entidades:

@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 codifica utilizando 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).


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. :)

Intentemos entender el problema. Creo que tus conceptos son "mentirosos". Primero dice que muchos problemas están asociados a las personas . Pero, entonces dices que una persona tiene muchos problemas feos (y no se relaciona con otros problemas ). Algo está mal con ese diseño.

Imagina cómo se mapeará en la base de datos. Usted tiene una sola herencia de tabla, entonces:

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

¿Cómo va a hacer hibernar la base de datos para hacer que el Problema solo se relacione con las Personas si su tipo de problema es IGUAL ? 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 .

PD .: Perdón por el dibujo feo: D


Descubrí 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.


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

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

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