【问题标题】:Remove entity and relations the correct way (JPA)以正确的方式删除实体和关系(JPA)
【发布时间】:2011-11-30 00:53:25
【问题描述】:

我有一个实体 Task 和一个用于它的 dao:TaskDao。 Task 实体具有到 Category 的 ManyToOne 映射。当我删除一个任务时,我还需要从类别中的集合中删除该任务:

// remove() method in TaskDao
public void remove (Task p_task) {
    // p_task is Detached, p_task.getCategory() is Detached
    p_task = em.merge(p_task);
    // p_task is Attached, p_task.getCategory() is Attached
    em.remove(p_task);
    // p_task is Detached, p_task.getCategory() is Attached
    p_task.getCategory().removeTask(p_task);
}

cmets 指示(此时)p_task 和/或 p_task.category 是否已附加/分离。首先让我解释一下为什么我选择这种陈述顺序。首先,我需要合并 p_task,以便附加 p_task.category,并且为了删除它需要合并的 p_task。 p_task 会在最后从类别集合中移除,因为 em.remove(p_task) 会抛出一个 ConstraintException,在这种情况下不应将任务从类别集合中移除。

这是正确的方法吗?另外,我很惊讶在 em.remove(p_task) 之后,p_task.category 仍然附加。

编辑:我应该给出一些实体类的代码。

public class Task implements Serializable {

    @JoinColumn(name = "category_id", referencedColumnName = "id")
    @ManyToOne(cascade = CascadeType.MERGE, optional = false)
    private Category category;

}

public class Category implements Serializable {

    @OneToMany(cascade = CascadeType.MERGE, mappedBy = "category")
    private List<Task> taskCollection;

    public void addTask (Task p_task) {
        if (taskCollection == null) {
            taskCollection = new ArrayList<>();
        }

        if (!taskCollection.contains(p_task)) {
            taskCollection.add(p_task);
        }
    }

    public void removeTask (Task p_task) {
        taskCollection.remove(p_task);
    }
}

在下面的代码中,p_task 被从 category.taskCollection 中移除,同时事务被回滚:

// remove() method in TaskDao
public void remove (Task p_task) {
    p_task = em.merge(p_task);
    p_task.getCategory().removeTask(p_task); // will not be rolled back if em.remove(p_task) throws an exception
    em.remove(p_task);
}

【问题讨论】:

    标签: jpa entity dao


    【解决方案1】:

    没关系,AFAIK。不过,您有一些不正确的假设:

    1. em.remove(p_task) 不会抛出 ConstraintException。冲洗就可以了。如果抛出这个异常,唯一要做的就是回滚事务并关闭实体管理器,因为它会使它处于不一致的状态。因此,在将任务从其类别中删除之前或之后删除它并没有太大区别。
    2. 您删除了一项任务,但没有删除该类别。那么为什么不附加该类别呢?

    【讨论】:

    • 1.但是 p_task.getCategory().removeTask(p_task) 语句不会回滚吧?这会导致 db 和内存数据之间存在不一致。 2.当我删除一个任务时,我不想删除关联的类别。我确实希望删除的任务超出 category.taskCollection。
    • 如果您回滚事务,则事务期间所做的所有修改都会回滚。如果您关闭会话,它在内存中保存的每个实体都将被分离,并且必须被认为是不一致的。你必须忘记他们。
    • 我使用 CMT,所以我实际上并不自己控制交易。您是否建议在调用 em.remove() 之前删除内存中的引用?
    • 没有。我要说的是,这样的异常应该导致事务回滚(只是让它沿着调用堆栈向上走)。我收到此异常,因为事务已回滚,实体删除(从数据库中)和实体删除(从其类别中)都将回滚,因此这两个操作的顺序无关紧要。
    【解决方案2】:

    这是正确的方法。您必须从集合中删除任务以确保集合功能。

    也许在合并之前检查 p_task 是否真的分离,以及任务是否 c

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      相关资源
      最近更新 更多