2

私は商用プロジェクトで Open JPA を使用しており、カスケードの Parent->Child の削除とマージを利用したいと考えています。

問題を示す作業コードをモックアップしました。

いくつかの子を持つ永続的な親オブジェクトがあります。Children のリレーションの 1 つを削除し、切り離された Parent をマージに渡します。トランザクションがコミットされると、UPDATE ステートメントが発行され、孤立した子を NULL 外部キーで更新しようとします。

@Entity
public class Parent implements Serializable {
    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
        private String desc;
    //@ElementDependent
    @OneToMany(mappedBy="parent", 
        cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}/*,orphanRemoval=true, fetch=FetchType.EAGER*/)
        private List<Child> childs = new ArrayList<Child>();

@Entity
public class Child implements Serializable {
    @Id private String desc;

    @ManyToOne
    private Parent parent;


    public class StackOverflowTest extends TestCase {
        private EntityManager em;
        private static EntityManagerFactory factory = Persistence.createEntityManagerFactory("SSICTest", System.getProperties());
        private Parent p;
        private Child c;
        private Child c2;

        public void testRemove() {
            prepareObjects();

            startTr();
            em.persist(p);
            commitTr();

            startTr();
            p = em.find(Parent.class, p.getId());
            em.remove(p);
            commitTr();
        }   
        public void testMerge() {
            prepareObjects();

            startTr();
            em.persist(p);
            commitTr();

            //remove on detached
            Child child = p.getChilds().get(0);
            p.getChilds().remove(child);
            child.setParent(null);
            startTr();

            em.merge(p);
            commitTr();

            startTr();
            p = em.find(Parent.class, p.getId());
            assertEquals(1, p.getChilds().size());
            commitTr();
        }
        protected void prepareObjects() {
            p = new Parent();       
            c = new Child();
            c2 = new Child();
            p.setDesc("desc");
            c.setDesc(Math.random()+"");
            c2.setDesc(Math.random()+"");
            p.getChilds().add(c);
            c.setParent(p);
            p.getChilds().add(c2);
            c2.setParent(p);
        }   
        void commitTr() {
            em.getTransaction().commit();
            em.close();
        }
        void startTr() {
            em = factory.createEntityManager();
            em.getTransaction().begin();
        }
    }

上記の例では、最初に説明したように、testRemove は正常に機能しますが、testMerge メソッドは機能しません。

@ElementDependent のコメントを削除すると、動作が異なります。

remove が Child にカスケードされておらず、参照整合性例外が db によってスローされ、testMerge が問題ないため、testRemove は失敗します。

orphanRemoval=true、fetch=FetchType.EAGER または @ForeignKey(deleteAction=ForeignKeyAction.CASCADE) の子の逆関係も役に立ちません。

お知らせ下さい。本当に助かりました!!

4

1 に答える 1

0
 @OneToMany(mappedBy="parent", 
    cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE},
    orphanRemoval=true, fetch=FetchType.EAGER)
 private List<Child> childs = new ArrayList<Child>();

 @ManyToOne
 private Parent parent;

orphanRemoval を true に設定します。orphanRemoval の目的を参照してください

于 2012-11-24T08:48:44.713 に答える