在 JPA 中可以将已删除的实体留在 @OneToMany 端的 collection 中吗?

Is it okay in JPA to leave a deleted entity in a collection at the @OneToMany side?

我正在做一个项目,我们在数据库中有两个实体副本,具有不同的 tables(它使用两个具有相同 classes 的持久性单元,但是映射其中之一的文件具有不同的 table 名称)。有一个工作副本和实时数据。对工作副本的更改可以应用到实时数据中,但也可以撤消。必须删除工作副本中创建的任何实体,必须再次使更新的实体与实时数据一致。

编辑可以指定是否更新其直接目标。如果它只更新实体层次结构中的后代,或创建一些新的后代,则 "target" 实体不会直接更改,也不必再次与实时数据同步。这很重要,因为撤消编辑可能会导致其他编辑 undone/deleted 以及它们碰巧影响相同的实体。我想尽可能减少这种 "side-effects"。

假设我们有一个 Course class 可以有任意数量的 Students。我希望关系是双向的。该课程有 collection 名学生,并在 @OneToMany 注释中指定 "mappedBy"。

@Entity
public class Course {

    // Primary key and other fields would be here...


    @OneToMany(mappedBy = "course", fetch = FetchType.LAZY)
    private List<Student> students;

    // Getters, setters...

}

学生 class 从数据库的角度来看是拥有方(它将具有课程 table 的外键)并指定 @JoinColumn.

@Entity
public class Student {

    // Primary key and other fields...

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "course_id")
    private Course course;

    // Getters and setters...

}

没有级联操作。不是 MERGE、PERSIST、REMOVE... 或任何东西。由于整个事情的运作方式,这些事情由编辑框架处理。整个过程在 Java EE 中运行,事务由容器处理。

编辑可能会创建新学生并将其添加到课程中。例如:

Course course;
// Fetch the course from persistence
Student student = new Student("John Doe");
student.setCourse(course);
course.getStudents().add(student);

为了保持数据模型的一致性,为学生设置了课程,在课程中也将学生添加到列表中。 course_id 栏在坚持学生后正确填写。

如果编辑未应用于实时数据但已撤消,则现在必须删除已创建的学生实体。那么出现的问题就是如何看待课程。从某种意义上说,它被更新了,因为它的 collection 中添加了一些东西。但是,不必对课程的数据库进行任何更改。它不是 RDBMS 中关系的拥有方。如果我们从实时数据中同步了课程,则可能需要撤消或删除对课程的其他更改。如果我们不这样做,他们可能会留下来。

假设我在一个 JTA 事务中并且注入了一个实体管理器。如果我从中获取学生并对它执行删除操作,我认为我不需要显式获取课程并从 collection 中删除学生。

问题:

  1. 如果我已经取了课程怎么办?
  2. 可以让学生留在collection吗?
  3. 因为它是托管实体,所以在事务结束时尝试合并课程会不会抛出异常?

假设事务中唯一会发生的事情以及其中的持久性上下文是此类实体的 deletion/syncing,因此 collection 会在短时间内不一致Java 边并不是真正的问题。如果它包含必须删除的实体,则框架代码会将其考虑在内,并且 objects 的保留时间不会超过交易的时间。

您的假设是正确的。由于没有操作从 Course 级联到 Student,并且 Course 不是拥有方,因此 JPA 提供程序将忽略 students 集合中的更改(以及没有更改) .

但是,如果为 students 集合启用了 second-level 缓存,那么您还需要从集合中删除已删除的学生,以便缓存中反映更改。

第一个概念,有必要将对象与映射分开,因为具有数据 x 的对象 X 的实例 x 不必存在于数据库中。

我们有一个类似的案例,用于历史管理的私人 ERP;如果将数据从一个 DB 传输到另一个(单元到另一个单元)时发生错误,JTA 将执行自动回滚。 Ant 你的问题的答案变成了:

  1. 如果您已经下载了课程,传输日期后没有问题,因为应用服务器的缓存已更新。
  2. 将学生留在集合中取决于实现,我们使用@statefull EJB,它允许我们释放对象。
  3. 当它尝试合并课程时不会抛出异常,因为合并方法将参数传递的实例数据复制到持久性中的托管实例上下文,如果没有相同ID的托管实体,则创建一个新的并复制数据,然后returns不需要的托管实例相同。