JPA OneToMany如何双向合并?

时间:2012-09-21 05:17:41

标签: java jpa

@OneToMany双向,EntityManger更新具有Task集合的ProjectValue时, EntityManger无法删除内存中程序删除的子Task。 是否会使用其他功能删除Task

DataStructure : 

    In ProjectPlan Table :
        PRPJ0001, First Poject
    In Task Table :
        AAA, AAA, PRPJ0001
        BBB, BBB, PRPJ0001
        CCC, CCC, PRPJ0001
    In Memory :
        PRPJ0001, First Poject
            AAA, AAA, PRPJ0001          -->  No Changes
            BBB, Change Name, PRPJ0001  -->  Need to update
                                        -->  Need to delete CCC
            NEW, NEW, PRPJ0001          -->  Need to add 

    Problem : Entity Manger cannot delete CCC;

    @Entity
    public class ProjectPlan {
        @Id
        private String id;
        private String name;
        @OneToMany(mappedBy = "projectPlan", targetEntity = Task.class, cascade = {CascadeType.ALL})
        private List<Task> taskList;

        public ProjectPlan(){}

        public ProjectPlan(String id, String name, List<Task> taskList) {
            this.id = id;
            this.name = name;
            this.taskList = taskList;
        }
        //getter & setter
    }

    @Entity
    public class Task {
        @Id
        private String id;
        private String name;
        @ManyToOne(targetEntity = ProjectPlan.class, cascade = {CascadeType.REFRESH})
        @JoinColumn(name = "projectId", referencedColumnName = "ID")
        private ProjectPlan projectPlan;

        public Task(){
        }

        public Task(String id, String name, ProjectPlan projPlan) {
            this.id = id;
            this.name = name;
            this.projectPlan = projPlan;
        }
        // getter & setter
    }

    public class Test {
        public static void main(String[] args) {
            EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPA");
            EntityManager em = emf.createEntityManager();
            /*
             Existing Data in Database
                List<Task> taskList = new ArrayList<Task>();
                ProjectPlan plan = new ProjectPlan("PRPJ0001", "First Poject", taskList);
                Task task1 = new Task("AAA","AAA", plan);
                Task task2 = new Task("BBB","BBB", plan);
                Task task3 = new Task("CCC","CCC", plan);
                taskList.add(task1);
                taskList.add(task2);
                taskList.add(task3);
            */

            em.getTransaction().begin();
            List<Task> taskList = new ArrayList<Task>();
            ProjectPlan plan = em.find(ProjectPlan.class, "PRPJ0001");

            /*Task "AAA" no changes*/
            Task task1 = new Task("AAA","AAA", plan);

            /*Task "BBB" updated info*/
            Task task2 = new Task("BBB","Change Name", plan);

            /*Task "CCC" removed*/

            /*Task "NEW" newly created*/
            Task task3 = new Task("NEW","NEW", plan);
            taskList.add(task1);
            taskList.add(task2);
            taskList.add(task3);

            plan.setTaskList(taskList);

            em.merge(plan);
            em.getTransaction().commit();
            em.close();
        }
    }

如果Task有另一个Sub Task List instance(递归关系),Task也将面临这种情况。我必须检查并检索需要实际删除的任务吗?您认为JPA应支持此功能吗?

2 个答案:

答案 0 :(得分:1)

在注释OneToMany上使用属性 orphanRemoval

<强>解释

当从关系中删除一对一或一对多关系中的目标实体时,通常需要将删除操作级联到目标实体。此类目标实体被视为“孤儿”,orphanRemoval属性可用于指定应删除孤立实体。

@Entity
public class ProjectPlan {
    @Id
    private String id;
    private String name;
    @OneToMany(mappedBy = "projectPlan", cascade = {CascadeType.ALL}, orphanRemoval=true)   // --> new attribute
    private List<Task> taskList;

    public ProjectPlan(){}

    public ProjectPlan(String id, String name, List<Task> taskList) {
        this.id = id;
        this.name = name;
        this.taskList = taskList;
    }
    //getter & setter
}

@Entity
public class Task {
    @Id
    private String id;
    private String name;
    @ManyToOne(cascade = {CascadeType.ALL})
    @JoinColumn(name = "projectId", referencedColumnName = "ID")
    private ProjectPlan projectPlan;

    public Task(){
    }

    public Task(String id, String name, ProjectPlan projPlan) {
        this.id = id;
        this.name = name;
        this.projectPlan = projPlan;
    }
    // getter & setter
}

答案 1 :(得分:0)

双向关联具有所有者方和反方。 Hibernate查看所有者方以了解是否存在关联。所有者方是具有mappedBy属性的方。因此,在这种情况下,所有者方是任务。

因此,如果要将任务CCC与其项目计划分离,则必须将其projectPlan字段设置为null。如果要删除任务CCC,则必须使用em.remove()删除它。