以正确的方式删除实体和关系(JPA)

问题描述:

我有一个实体Task和一个道具:TaskDao。任务实体具有到类别的ManyToOne映射。当我删除任务,我还需要从集合中删除的任务类别:以正确的方式删除实体和关系(JPA)

// 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); 
} 

评论表明(在这一点),如果P_TASK和/或p_task.category的安装/拆卸。首先让我解释一下为什么我选择这个顺序。首先,我需要合并p_task,以便p_task.category被附加,并且为了移除它需要合并的p_task。因为em.remove(p_task)可以抛出ConstraintException,所以p_task从类别集合中被移除,这种情况下不应该从类别集合中删除该任务。

这是正确的认同?另外,在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); 
} 

这是确定的,据我所知。但是,您有一些不正确的假设:

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

1.但p_task.getCategory()。removeTask(P_TASK)语句不会回滚,对不对?这会在数据库和内存数据之间留下不一致。 2.当我删除任务时,我不想删除关联的类别。我确实希望从category.taskCollection中删除已删除的任务。 – BigJ

+0

如果回滚事务,则在事务期间完成的每​​个修改都会回滚。如果关闭会话,它在内存中保存的每个实体都会被分离,并且必须被视为不一致。你必须忘掉它们。 –

+0

我使用CMT,所以我自己实际上并不控制事务。你会建议在调用em.remove()之前删除内存中的引用吗? – BigJ

它是正确的答案。您必须从集合中删除任务以确保集合的功能。

也许检查P_TASK被合并前,如果真的任务分离Ç