【问题标题】:Is it okay in JPA to leave a deleted entity in a collection at the @OneToMany side?在 JPA 中可以将已删除的实体留在 @OneToMany 一侧的集合中吗?
【发布时间】:2017-01-24 13:07:42
【问题描述】:

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

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

假设我们有一个Course 类,它可以有任意数量的Students。我希望关系是双向的。该课程有一组学生,并在@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...

}

从数据库的角度来看,学生类是拥有方(它将具有 Course 表的外键)并指定 @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 列在持久化学生时正确填写。

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

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

问题:

  1. 如果我已经获取了课程怎么办?
  2. 可以将学生留在集合中吗?
  3. 当它尝试在事务结束时合并课程时是否会抛出异常,因为它是一个托管实体?

假设事务中唯一会发生的事情以及其中的持久性上下文是删除/同步这些实体,因此在 Java 端的集合会在短时间内不一致并不是真正的问题。如果它包含必须删除的实体,框架代码将考虑它,并且对象的保留时间不会超过事务。

【问题讨论】:

    标签: java jpa jakarta-ee bidirectional consistency


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-07-09
        • 1970-01-01
        • 1970-01-01
        • 2015-07-19
        • 2016-08-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多