Pregunta

@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 intentando hacer.Espero que la persona @ManyToOne sea heredada por la clase UglyProblem.Pero habrá una excepción que diga algo como:"No se encuentra ninguna propiedad de este tipo en la clase UglyProblem (mappedBy="persona")".

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


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

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

public class A {
    private int foo;
}

@Entity
public class B extens A {
}

luego campo foo no se asignará 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;
}
}

Espero que la clase UglyProblem tenga archivos id y name y ambas clases se asignarán utilizando la misma tabla.(De hecho, esto es exactamente lo que sucede, acabo de comprobarlo de nuevo).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.

Espero eso 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í, vi eso.De hecho, utilicé una solución de sólo 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 por eso pregunté.

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

(si te interesa cómo he enfrentado este problema:Heredé un proyecto creado con hibernación 3.Era Jboss 4.0. Algo + hibernación ya estaba allí (lo descargarías todo junto).Estaba moviendo este proyecto a Jboss 4.2.2 y descubrí que hay asignaciones heredadas de "@OneToMany mappedBy" y funcionó bien en la configuración anterior...)

¿Fue útil?

Solución

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

Intentemos comprender el problema.Creo que tus conceptos son "mentirosos".Primero dices que muchos Problemas están asociados a Gente.Pero luego dices eso Persona tener muchos problema feos (y no se relaciona con otros Problemas).Algo anda mal con ese diseño.

Imagínese cómo se asignará a la base de datos.Tienes una herencia de tabla única, entonces:

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

¿Cómo Hibernate va a hacer cumplir la base de datos para hacer Problema sólo se relacionan con Gente si es tipo de problema ¿Es igual ARRIBA?Ese es un problema muy difícil de resolver.Entonces, si desea este tipo de relación, cada subclase debe estar en su propia tabla.eso es lo que @MappedSuperclass hace.

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

Otros consejos

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 muy limpio, es añadir el propietario Hibernate @Dónde cláusula de la asociación @OneToMany para forzar el tipo en consultas:

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

Desafortunadamente, según Hibernate documentación "Se ignoran las propiedades de las superclases no mapeadas como @MaptSuperClass". Yo también corrí contra esto.Mi solución fue representar la herencia deseada a través de interfaces en lugar de los propios beans de 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 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 codifica utilizando las interfaces en lugar de los beans de entidad reales que implementan esas interfaces, será más fácil cambiar las asignaciones subyacentes más adelante (menos riesgo de romper la compatibilidad).

Creo que necesitas anotar tu Problema superclase con @MappedSuperclass en lugar de @Entidad.

Descubrí cómo solucionar 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 La @ForceDiscriminator hace que el @OneToMany honre al discriminador

Requiere anotaciones de hibernación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top