2012-10-12 108 views
5

Tengo dos modelos.Hibernate (JPA) múltiple @OneToMany para el mismo modelo

@Entity 
public class Student 
{ 
    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    protected long id; 

    @? 
    protected Address homeAddress; 

    @? 
    protected Address schoolAddress; 
} 

@Entity 
public class Address 
{ 
    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    protected long id; 

    @? 
    protected List<Student> students; 
} 

Lo APP/hibernación anotaciones necesito para poner por encima de homeAddress, schoolAddressstudents y para hacer el trabajo asociación?

Por supuesto que probé muchas cosas y nada funcionó. Por ejemplo, establecer

@ManyToOne 
    @JoinColumn (name="student_homeAddress_id", updatable = false, insertable = false) 
    protected Address homeAddress; 

    @ManyToOne 
    @JoinColumn (name="student_schoolAddress_id", updatable = false, insertable = false) 
    protected Address schoolAddress; 

y

@OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, fetch = FetchType.EAGER) 
    @JoinColumns({ 
    @JoinColumn(name = "student_homeAddress_id", referencedColumnName = "student_homeAddress_id"), 
    @JoinColumn(name = "student_schoolAddress_id", referencedColumnName = "student_schoolAddress_id")}) 
    @IndexColumn(name="students_index") 
    protected List<Student> students; 

yealds Unable to find column with logical name: student_homeAddress_id in org.hibernate.mapping.Table(Address) and its related supertables and secondary tables. también trató usando mappedBy sino que toma un solo argumento (no se puede hacer mappedBy="student_homeAddress_id, student_schoolAddress_id".

también examinó mover el JoinColumns a la tableta Student pero no estoy seguro de lo que las anotaciones deben parecerse a OneToMany y ManyToOne ya que tengo varias direcciones ahí que JoinColumns no tiene mucho sentido

lo que hizo el trabajo, pero no estaba creando las asociaciones fue tener:.

@OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH}, fetch = FetchType.EAGER) 
    @JoinColumn(name="address_id") 
    @IndexColumn(name="students_index") 
    protected List<Student> students; 

uso de este, cuando se almacena en la base de datos de los modelos, el student_homeAddress_id y student_schoolAddress_id siempre fueron nulas incluso después de almacenar ambos extremos (el modelo de Estudiante y Dirección).

Mi pensamiento es que en la mesa Address habrá 3 columnas adicionales: student_homeAddress_id (el id del Estudiante en la Tabla de alumnos para el homeAddress), student_schoolAddress_id (el id del Estudiante en la Tabla de alumnos para el schoolAddress) y students_index (la ubicación basada en 0 en la lista students). Eso debería ser suficiente, ¿correcto?

¿Alguna idea?

¡Muchas gracias!

Respuesta

3

Intentamos la sugerencia de mael pero no pudimos hacerlo funcionar.

Terminamos siguiendo this que funcionó.

En otras palabras, tenemos OneToMany relaciones:

En Student:

protected List<AddressStudentAssociation> addresses; 

En Address:

protected List<AddressStudentAssociation> students; 

Y en AddressStudentAssociation:

@ManyToOne 
@PrimaryKeyJoinColumn(name="STUDENTID", referencedColumnName="id") 
private Student student; 
@ManyToOne 
@PrimaryKeyJoinColumn(name="ADDRESSID", referencedColumnName="id") 
private Address address; 

más un argumento para separar una dirección de la otra (isHome).

Finalmente, dentro de Student tenemos public Address getHomeAddress() que atraviesa la lista addresses y devuelve la dirección correcta. También tuvimos que jugar con las anotaciones para que funcione. No es óptimo en general pero funciona y ya pasamos demasiado tiempo tratando de hacer que las cosas funcionen. : |

4

Si tiene una entidad que quiere relacionar @OneToMany en más de un campo, debe usar @JoinTable para que Hibernate pueda generar 2 tablas para la relación.

Desde el javadoc @JoinTable:

Una tabla de unión se utiliza normalmente en el mapeo de muchos-a-muchos y asociaciones unidireccionales uno-a-muchos. También se puede usar para mapear asociaciones bidireccionales de muchos a uno/uno a muchos, relaciones unidireccionales uno a uno y asociaciones de uno a uno (ambos bidireccional y unidireccional).

Cuando se utiliza una tabla de unión en la cartografía de una relación con una clase incrustada en la parte propietaria de la relación, la entidad que contiene en lugar de la clase incrustada se considera el dueño de la relación .

Si falta la anotación de JoinTable, se aplican los valores predeterminados de los elementos de anotación .El nombre de la tabla de unión se supone que es , los nombres de tabla de las tablas primarias asociadas concatenadas juntas (propietario primero) usando un guión bajo.

Tome este ejemplo:

@Entity 
@Indexed(index = "causa_penal") 
@Table(name = "causas_penales") 
public class CausaPenal implements Serializable { 



    @Id 
    @GeneratedValue(strategy = GenerationType.TABLE) 
    @Column(name = "id") 
    @DocumentId 
    private Integer id; 

    @Version 
    @Column(name = "opt_lock") 
    private Integer version; 

    @ManyToMany(cascade = { CascadeType.ALL }) 
    @JoinTable(name = "causapenal_imputados") 
    @IndexedEmbedded(depth = 1) 
    private List<ParteMaterial> imputados; 

    @ManyToMany(cascade = CascadeType.ALL) 
    @JoinTable(name = "causapenal_victimas") 
    @IndexedEmbedded(depth = 1) 
    private List<ParteMaterial> victimas; 

    //Getters and Setters 
} 

Como se puede ver, tengo CausaPenal señalando ParteMaterial dos veces. Pero necesito que esa lista sea independiente la una de la otra. Entonces con @JoinTable le digo a Hibernate que esta relación debe ser mapeada con 4 tablas: "causa_penal" para la entidad CausaPenal, "causa_penal_imputados" para la relación de CausaPenal y el campo imputados que está mapeado a una Entidad ParteMaterial y lo mismo para victimas y finalmente, la tabla para ParteMaterial Entity.