Hibernate(JPA)为同一模型多个@OneToMany

时间:2022-09-11 13:41:13

I have two models.

我有两个型号。

@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;
}

What JPA/hibernate annotations do I need to put above homeAddress, schoolAddress and students to make the association work?

我需要在homeAddress,schoolAddress和学生之上放置哪些JPA / hibernate注释才能使关联工作?

Of course I've tried many things and nothing worked. For example, setting

当然,我尝试了很多东西,没有任何效果。例如,设置

    @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;

and

    @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. Also tried using mappedBy but that takes a single argument (can't do mappedBy="student_homeAddress_id, student_schoolAddress_id".

yealds无法找到具有逻辑名称的列:org.hibernate.mapping.Table(Address)中的student_homeAddress_id及其相关的supertable和辅助表。还尝试使用mappedBy但是只接受一个参数(不能执行mappedBy =“student_homeAddress_id,student_schoolAddress_id”)。

Also looked into moving the JoinColumns to the Student tablet but I am not sure what the annotations should look like for OneToMany and ManyToOne as I have multiple Addresses there which JoinColumns doesn't make much sense.

还研究了将JoinColumns移动到学生平板电脑但我不确定OneToMany和ManyToOne的注释应该是什么样的,因为我有多个地址,其中JoinColumns没有多大意义。

The thing that did work but was not creating the associations was having:

确实有效但未创建关联的事情是:

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

Using this, when storing in the DB the models, the student_homeAddress_id and student_schoolAddress_id were always null even after storing both ends (the Student and Address model).

使用此功能,当在DB中存储模型时,即使存储了两端(Student和Address模型),student_homeAddress_id和student_schoolAddress_id也始终为null。

My thought is that on the Address table there will be 3 extra columns: student_homeAddress_id (the id of the Student in the Student table for the homeAddress), student_schoolAddress_id (the id of the Student in the Student table for the schoolAddress) and students_index (the 0-based location on the students list). That should suffice, correct?

我的想法是,在地址表上将有3个额外的列:student_homeAddress_id(homeAddress的Student表中Student的id),student_schoolAddress_id(studentAddress的Student表中Student的id)和students_index(the学生名单上的0位置)。这应该足够了,对吗?

Any ideas?

Thanks a lot!

非常感谢!

2 个解决方案

#1


4  

If you have an entity which you want to relate @OneToMany in more than one field you should use @JoinTable so Hibernate can generate 2 tables for the relationship.

如果你有一个想要在多个字段中关联@OneToMany的实体,你应该使用@JoinTable,这样Hibernate可以为关系生成2个表。

From the @JoinTable javadoc:

来自@JoinTable javadoc:

A join table is typically used in the mapping of many-to-many and unidirectional one-to-many associations. It may also be used to map bidirectional many-to-one/one-to-many associations, unidirectional many-to-one relationships, and one-to-one associations (both bidirectional and unidirectional).

连接表通常用于多对多和单向一对多关联的映射。它还可用于映射双向多对一/一对多关联,单向多对一关系以及一对一关联(双向和单向)。

When a join table is used in mapping a relationship with an embeddable class on the owning side of the relationship, the containing entity rather than the embeddable class is considered the owner of the relationship.

当连接表用于在关系的拥有方映射与可嵌入类的关系时,包含实体而不是可嵌入类被视为关系的所有者。

If the JoinTable annotation is missing, the default values of the annotation elements apply. The name of the join table is assumed to be the table names of the associated primary tables concatenated together (owning side first) using an underscore.

如果缺少JoinTable注释,则应用注释元素的默认值。假设连接表的名称是使用下划线连接在一起(首先拥有一侧)的关联主表的表名。

Take this example:

举个例子:

@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
}

As you can see, I have CausaPenal pointing to ParteMaterial twice. But I need those list to be independent of each other. So with @JoinTable I tell Hibernate that this relationship must be mapped with 4 tables: "causa_penal" for the CausaPenal entity, "causa_penal_imputados" for the relationship of CausaPenal and the imputados field which is mapped to a ParteMaterial Entity and the same for victimas and finally, the table for ParteMaterial Entity.

如你所见,我让CausaPenal指向ParteMaterial两次。但我需要这些清单彼此独立。因此,对于@JoinTable,我告诉Hibernate这个关系必须映射到4个表:CausaPenal实体的“causa_penal”,CausaPenal与imputados字段的关系的“causa_penal_imputados”,映射到ParteMaterial实体,并且对于victima和最后,ParteMaterial Entity的表。

#2


4  

We tried mael's suggestion but we couldn't make it work.

我们尝试了mael的建议,但我们无法使其发挥作用。

We ended up following this which worked.

我们最终遵循了这个有效的方法。

In other words, we have OneToMany relations:

换句话说,我们有OneToMany关系:

On Student:

protected List<AddressStudentAssociation> addresses;

On Address:

protected List<AddressStudentAssociation> students;

And on AddressStudentAssociation:

在AddressStudentAssociation上:

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

plus an argument to separate the one address from the other (isHome).

加上一个参数将一个地址与另一个地址分开(isHome)。

Finally, inside Student we have public Address getHomeAddress() which traverses the addresses list and returns the correct address. We also had to play with the annotations to make it work. Not optimal in general but it works and we already spent too much time trying to make things work. :|

最后,在Student内部,我们有公共地址getHomeAddress(),它遍历地址列表并返回正确的地址。我们还必须使用注释来使其工作。一般来说不是最佳的但是它有效并且我们已经花费了太多时间来努力使事情发挥作用。 :|

#1


4  

If you have an entity which you want to relate @OneToMany in more than one field you should use @JoinTable so Hibernate can generate 2 tables for the relationship.

如果你有一个想要在多个字段中关联@OneToMany的实体,你应该使用@JoinTable,这样Hibernate可以为关系生成2个表。

From the @JoinTable javadoc:

来自@JoinTable javadoc:

A join table is typically used in the mapping of many-to-many and unidirectional one-to-many associations. It may also be used to map bidirectional many-to-one/one-to-many associations, unidirectional many-to-one relationships, and one-to-one associations (both bidirectional and unidirectional).

连接表通常用于多对多和单向一对多关联的映射。它还可用于映射双向多对一/一对多关联,单向多对一关系以及一对一关联(双向和单向)。

When a join table is used in mapping a relationship with an embeddable class on the owning side of the relationship, the containing entity rather than the embeddable class is considered the owner of the relationship.

当连接表用于在关系的拥有方映射与可嵌入类的关系时,包含实体而不是可嵌入类被视为关系的所有者。

If the JoinTable annotation is missing, the default values of the annotation elements apply. The name of the join table is assumed to be the table names of the associated primary tables concatenated together (owning side first) using an underscore.

如果缺少JoinTable注释,则应用注释元素的默认值。假设连接表的名称是使用下划线连接在一起(首先拥有一侧)的关联主表的表名。

Take this example:

举个例子:

@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
}

As you can see, I have CausaPenal pointing to ParteMaterial twice. But I need those list to be independent of each other. So with @JoinTable I tell Hibernate that this relationship must be mapped with 4 tables: "causa_penal" for the CausaPenal entity, "causa_penal_imputados" for the relationship of CausaPenal and the imputados field which is mapped to a ParteMaterial Entity and the same for victimas and finally, the table for ParteMaterial Entity.

如你所见,我让CausaPenal指向ParteMaterial两次。但我需要这些清单彼此独立。因此,对于@JoinTable,我告诉Hibernate这个关系必须映射到4个表:CausaPenal实体的“causa_penal”,CausaPenal与imputados字段的关系的“causa_penal_imputados”,映射到ParteMaterial实体,并且对于victima和最后,ParteMaterial Entity的表。

#2


4  

We tried mael's suggestion but we couldn't make it work.

我们尝试了mael的建议,但我们无法使其发挥作用。

We ended up following this which worked.

我们最终遵循了这个有效的方法。

In other words, we have OneToMany relations:

换句话说,我们有OneToMany关系:

On Student:

protected List<AddressStudentAssociation> addresses;

On Address:

protected List<AddressStudentAssociation> students;

And on AddressStudentAssociation:

在AddressStudentAssociation上:

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

plus an argument to separate the one address from the other (isHome).

加上一个参数将一个地址与另一个地址分开(isHome)。

Finally, inside Student we have public Address getHomeAddress() which traverses the addresses list and returns the correct address. We also had to play with the annotations to make it work. Not optimal in general but it works and we already spent too much time trying to make things work. :|

最后,在Student内部,我们有公共地址getHomeAddress(),它遍历地址列表并返回正确的地址。我们还必须使用注释来使其工作。一般来说不是最佳的但是它有效并且我们已经花费了太多时间来努力使事情发挥作用。 :|