【问题标题】:Can a JPA entity have multiple OneToMany associations?一个 JPA 实体可以有多个 OneToMany 关联吗?
【发布时间】:2015-07-19 07:23:36
【问题描述】:

向我的实体类添加两个OneToMany 关联似乎不起作用。如果我删除其中一个,它会正常工作。

@Entity
@Table(name = "school")
public class School {

    private List<Teacher> teachers;
    private List<Student> students;

    @OneToMany(cascade=CascadeType.ALL, mappedBy = "school", fetch = FetchType.EAGER)
    public List<Teacher> getTeachers()
        return this.teachers;
    }
    public void setTeachers(List<Teacher> teachers) {
         this.teachers = teachers;
    }

    @OneToMany(cascade=CascadeType.ALL, mappedBy = "school", fetch = FetchType.EAGER)
    public List<Student> getStudents()
        return this.students;
    }
    public void setStudents(List<Student> teachers) {
         this.students = students;
    }
}

然后在TeacherStudent 我有正确的ManyToOne 注释

@Entity
@Table(name = "teacher")
public class Teacher {
    private School school;

    @ManyToOne
    @JoinColumn(name = "school_id")
    public School getSchool() {
        return this.school;
    }
    public void setSchool(School school) {
        this.school = school;
    }
}

@Entity
@Table(name = "student")
public class Student {
    private School school;

    @ManyToOne
    @JoinColumn(name = "school_id")
    public School getSchool() {
        return this.school;
    }
    public void setSchool(School school) {
        this.school = school;
    }
}

我也有带有正确注释的 id 字段(@Id@GeneratedValue

所以对我来说,我在同一个班级中似乎不能有多个@OneToMany。这是正确的吗?

【问题讨论】:

  • 不,这根本不正确。您可以拥有任意数量的它们。你是什​​么意思“它不起作用”?
  • 可能是两个关系同名的问题?
  • 检索用户时,数据库没有返回任何内容。没有堆栈跟踪,甚至没有警告。我可以看到hibernate正在映射所有类
  • @Jens 变量在两个类中都称为school,因此它们必须具有相同的mappedBy 值,不是吗?
  • 那么hibernate执行的是什么sql语句?

标签: java hibernate jpa orm hibernate-mapping


【解决方案1】:

为什么 FetchType.EAGER 是个坏主意

您可以有多个一对多关联,只要只有一个是 EAGER。

但是,即使您可以使用Set 而不是List 来绕过这个MultipleBagFetchException,这也不是一件好事,因为您最终会得到一个笛卡尔积。

避免笛卡尔积

最好的办法是根本不使用 EAGER。您应该对所有关联使用 LAZY,并使用 JOIN FETCH JPQL 指令急切地获取多个 many-to-oneone-to-one 关联和最多一个 one-to-many 关联。

如果您想获取多个one-to-many 关联,您可以使用Hibernate.initialize(proxy) 方法进行第二或第三关联。

获取多个父集合以及多个子集合

但是,如果您有一个需要加载多个子关联的父实体集合,那么您可以将JOIN FETCH 用于第一个集合,因为如果您尝试急切地获取多个子集合,那么您最终会使用笛卡尔积。

所以,假设您想要获取多个 Post 父实体及其 commentstags 集合,您可以在第一个查询中获取 comments

List<Post> _posts = entityManager
.createQuery(
    "select distinct p " +
    "from Post p " +
    "left join fetch p.comments " +
    "where p.id between :minId and :maxId ", Post.class)
.setParameter("minId", 1L)
.setParameter("maxId", 50L)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();

并且,对于第二个tags 集合,您可以发出以下辅助查询:

_posts = entityManager
.createQuery(
    "select distinct p " +
    "from Post p " +
    "left join fetch p.tags t " +
    "where p in :posts ", Post.class)
.setParameter("posts", _posts)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();

这是如何工作的?

第一个查询获取附加到当前EntityManagerPost 实体。为每个Post 实体获取comments 集合,但tags 集合由代理表示。

第二个查询将获取tags,但由于Hibernate 已经缓存了Post 实体,它只会将tags 代理集合替换为从数据库中获取的实际tags 条目。

【讨论】:

  • 我将在今天晚些时候尝试一下,如果可行,请接受您的回答。提前感谢,我一直有一段时间的问题
  • 如果 OneToMany 中的一个被 Just @ManyToOne 在两个拥有方 中使用相同的名称删除怎么办?
【解决方案2】:

我认为您的 @ManyToOne 和 @JoinColumn 注释应该放在教师和学生类型的私立学校属性上。我注意到您在它们的公共 getter 方法中都有它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 2015-03-07
    • 2014-07-12
    • 2020-12-04
    • 1970-01-01
    相关资源
    最近更新 更多