【发布时间】:2019-01-02 12:10:10
【问题描述】:
我似乎很难理解 JPA 以及 OneToMany 关系的实际运作方式。
例如,假设我有一个对象Class
@Entity
public class Class {
@Id
private String className;
@OneToMany(cascade = Cascade.ALL, orphanRemoval = true)
private Set<Student> students;
// Constructors, Getters, Setter
}
我还有一个对象 Student,它包含 Class。
@Entity
public class Student {
@Id
private String studentName;
@ManyToOne
private Class class;
// Constructors, Getters, Setter
}
显然,一个学生可以有多个班级,但忘了这一点。
为什么当我创建一个班级,然后使用该班级创建几个学生时,ClassRepository 上的findAll() 会返回一组空的学生。
Class class = new Class("CS", new HashSet<>());
classRepository.save(class); // repository has no special functions
Student student1 = new Student("1", class);
Student student2 = new Student("2", class);
studentRepository.save(student1);
studentRepository.save(student2);
classRepository.findAll() // Returns me a List<Class> with only one class object that has an empty set.
我在想上面的代码应该自动看到这两个学生来自那个班级,所以当我调用 buildingRepository.findAll() 时,它将返回一个 Class 对象,其中学生设置正确。
那我理解错了吗?还是我的代码错了?我怎样才能改变它来修复它?
【问题讨论】:
-
几个原因:1.你的映射不正确; 2.您正在设置学生班级,但您没有将学生添加到班级。以下是必须映射双向 OneToMany 的方式:docs.jboss.org/hibernate/orm/current/userguide/html_single/…
-
默认情况下,
@...Many是延迟加载的,这是解决性能问题的最佳选择。当您使用Cascade.ALL时,您可以让Classpersist 您的学生。对我来说,classRepository.findAll()只返回 1 个类是正常的,因为你只坚持了 1 个。对于性能问题,我建议你在单独的请求中加载学生,而不是使用classRepository.findAll()。喜欢classRepository.findClassWithAllStudentsById()并使用EntityGraph加载学生。 -
您应该将 from 对象
class映射到student。不分开!例如,您可以使用 Json 映射格式。 -
@JBNizet 我不应该使用班级对象保存两个学生,将学生添加到班级吗?我希望它在这样做时将那些学生保存到课堂上。就像我最后提供的示例代码是我希望我的逻辑工作的方式。因此,当我执行
classRepo.findAll()时,它应该返回一个class,而该集合具有两个student对象。 -
如果您的映射是正确的,那么您所做的就足以将关联保存到数据库。如果您清除了持久性上下文或者如果您开始一个新的,那么检索该类将检索其学生。但是在该持久性上下文中,由于您保存的是一个没有任何学生的班级,因此您将检索到的是那个没有任何学生的精确班级:您有责任在持久性上下文(即事务)中保持图形的连贯性
标签: java spring-boot spring-data-jpa