2016-12-14 2 views
0

大規模なJPAアノテート・エンティティを介してカスケード作成とマージを行う必要があるWebSphere 8.5.5(OpenJPA 2.2.3)のプロジェクトで作業しています。モデル。 grand-parents上でEntityManager.merge()を呼び出すか、トランザクションのコミット時にトリガーされたフラッシュによってgrand-childrenをマージする際には、非常に具体的な問題があります。ここでは詳細は以下のとおりです。エンティティのマッピングのコンパウンドEmbeddedId(別のEmbeddedIdを含むEmbeddedId)を使用してJPAエンティティを挿入する

関連部分:

  1. エンティティAはEntityBがEntityC
  2. にoneToMany
  3. EntityCがEntityD
にoneToManyを持っていEntityBにoneToMany
  • を持っています

    すべてが双方向マッピングを持っています。エンティティAとBには、単一列の主キーがあります。エンティティCには、エンティティBの主キーに対する外部キーを含む複合主キーがあります。エンティティDには、エンティティCの複合キーを含む複合キーがあります。以下のマッピングを参照してください。

    あなたはインクルードが正しく持続カスケードうとモデル(接続されているすべての子供たちと一緒に)エンティティAのEntityManager.persist()を呼び出すことができますどのような作品

    @Entity 
    @Table(name="TableA") 
    public class EntityA extends BaseEntity { 
    
        @Id 
        @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="TABLE_A_ID_GEN") 
        @SequenceGenerator(name="TABLE_A_ID_GEN", sequenceName="TABLE_A_ID", allocationSize=1) 
        @Column(name="TABLE_A_ID") 
        private Integer id; 
    
        @OneToMany(fetch=FetchType.LAZY, mappedBy="entityA", cascade=CascadeType.ALL) 
        private List<EntityB> entityBList; 
    
        ... 
    
    } 
    
    @Entity 
    @Table(name="TableB") 
    public class EntityB extends BaseEntity { 
    
        @Id 
        @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="TABLE_B_ID_GEN") 
        @SequenceGenerator(name="TABLE_B_ID_GEN", sequenceName="TABLE_B_ID", allocationSize=1) 
        @Column(name="TABLE_B_ID") 
        private Integer id; 
    
        @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL) 
        @JoinColumn(name="TABLE_A_ID") 
        private EntityA entityA; 
    
        @OneToMany(fetch=FetchType.LAZY, mappedBy="entityB", cascade=CascadeType.ALL) 
        private List<EntityC> entityCList; 
    
        ... 
    
    } 
    
    @Entity 
    @Table(name="TableC") 
    public class EntityC extends BaseEntity { 
    
        @EmbeddedId 
        private EntityC_PK id = new EntityC_PK(); 
    
        @MapsId("entityB_Id") 
        @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL) 
        @JoinColumn(name="TABLE_B_ID") 
        private EntityB entityB; 
    
        @OneToMany(fetch=FetchType.LAZY, mappedBy="entityC", cascade=CascadeType.ALL) 
        private List<EntityD> entityDList; 
    
        ... 
    
    } 
    
    @Embeddable 
    public class EntityC_PK implements BaseComponent { 
    
        @Column(name="TABLE_B_ID", nullable = false, updatable = false) 
        private Integer entityB_Id; 
    
        @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="TABLE_C_ID_GEN") 
        @SequenceGenerator(name="TABLE_C_ID_GEN", sequenceName="TABLE_C_ID", allocationSize=1) 
        @Column(name="TABLE_C_ID") 
        private Integer entityC_Id; 
    
        ... 
    
    } 
    
    @Entity 
    @Table(name="TABLE_D") 
    public class EntityD extends BaseEntity { 
    
        @EmbeddedId 
        private EntityD_PK id = new EntityD_PK(); 
    
        @MapsId("entityC_Id") 
        @JoinColumns({ 
         @JoinColumn(name = "TABLE_B_ID"), 
         @JoinColumn(name = "TABLE_C_ID")}) 
        @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL) 
        private EntityC entityC; 
    
        ... 
    
    } 
    
    @Embeddable 
    public class EntityD_PK implements BaseComponent { 
    
        @Embedded 
        private EntityC_PK entityC_Id; 
    
        @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="TABLE_D_ID_GEN") 
        @SequenceGenerator(name="TABLE_D_ID_GEN", sequenceName="TABLE_D_ID", allocationSize=1) 
        @Column(name="TABLE_D_ID") 
        private Integer entity_id; 
    
        ... 
    
    } 
    

    。あなたはEntityManager.persist(エンティティA)のエンティティAをインスタンス化して呼び出す場合

    とTHENなどの子供、孫を、追加するときEntityManager.merge(エンティティA)(または許可:

    何をして動作しませんトランザクションをコミットする際の暗黙的なマージ)、正しい順序でINSERTステートメントを実行することができません。物事をより混乱させるために、INSERTの順序は単体テストの繰り返し実行全体で一貫していません。マージ時に

    我々は正しい挿入順序を強制(および更新/削除)するJPA注釈を修正方法:これは、エンティティC.

    前に質問をエンティティDを挿入しようとすることで失敗しましたか?

    EDIT 1: データベースが制約との外部キーの関係を強制するため、挿入/削除の順序が重要です。

  • +0

    ここに私の答えを見てください:http://stackoverflow.com/questions/39024310/openjpa-nested-onetomany-relationships-merge-issue/39025865#39025865 –

    答えて

    2

    シナリオのJPA仕様を見直さなければならないことを最初に述べておきましょう(そしておそらく、私は明白ですが、ごめんなさい)。次に、あなたは 'EntityManager.create()'と述べますが、あなたは.persistを意味すると思いますか?あなたは後でマージについて話すので、マージを意味するかもしれない。いずれにしても、マージではなく新しいエンティティを永続化する場合は、.persistを使用することをお勧めします。それは違法ではありませんが、通常は分離されたエンティティなどをマージするためにマージされます。

    あなたの質問の中心に来て、あなたの注文に役立つプロパティを教えてください。 ddlに外部キー制約が含まれていると、テキストには記載されませんでした。あなたは秩序に関心があるので、私はそのような制約があると思います。あなたがそうした場合、OpenJPAはこの制約について何も知らないので、物事を適切に注文することを知らないでしょう。デフォルトでは、SQLの順序に依存することはできません。順序のランダム性は、まさに私が期待しているものです。ただし、FK制約をサポートするような方法で注文する必要がある場合は、OpenJPAに制約についての「学習」を許可する必要があります。これを行うには、このプロパティを永続的に設定する必要があります。xmlファイル(またはあなたがJVMのカスタムプロパティとして設定することができます):

    <property name="openjpa.jdbc.SchemaFactory" value="native(ForeignKeys=true)"/> 
    

    このプロパティは、OpenJPAのは、あなたのスキーマを検査することができますので、それはあなたのFK制約について学ぶことができやっインチその知識によって、OpenJPAはSQLを適切に順序付けることができます。最後に

    、あなたがFK制約を持っていませんが、特定の方法でSQLを注文したい場合、あなたはこれを使用する必要がある可能性がある場合:ん

    <property name="openjpa.jdbc.UpdateManager" value="operation-order"/> 
    

    はないし、私は繰り返し両方のプロパティを同時に使用しないでください。それは奇妙な副作用を持つことができます。最初にSchemaFactoryプロパティにフォーカスし、UpdateManagerの試行に役立たない場合は、操作命令は、OpenJPAに、エンティティの保持方法、つまり操作の順序に基づいてSQLを順序付けるよう指示します。これは実際にあなたの状況にはあまり役立たないかもしれません。それは、Aを持続させ、他のすべてがカスケードされることを期待するからです(OpenJPAはおそらく最初のものですが、BとCの場合は先に行く)。しかし、A、C、Bを永続化した場合、SQLはA、C、Bの順に挿入し、「操作順序」を設定します。

    +0

    あなたの役に立つ答えをヒースにありがとう。私はあなたのソリューションと正確に一致するより多くの情報を見つけました。 [link](http://openjpa.208410.n2.nabble.com/Inconsistent-execution-order-of-INSERT-statements-using-cascading-persist-td678745.html)。あなたが言及していないオプションの1つは、OpenJPAの@ForeignKeyアノテーションを使用して、どの関係に外部キーがあり、特定の挿入順序が必要かを示すことでした。 –

    +1

    ありがとう!私は故意にそれを残しました(多分私は持ってはいけない)。 OpenJPAの「@ForeignKey」には2つの問題があります.1)それは妥当です。 2)それは開発者にすべての正しい場所に「@ForeignKey」を入れようとする責任を負う(1つのスポットを欠き、すべてのベットはオフ)。あなたのケースでは、いくつかのクラスでは大したことはありませんが、大きなアプリではそれが難しくなります。私は '@ FK'を使わないとは言いませんが、あなたのドメインモデルの右の場所に '@FK'を追加することで、コード変更なしで1行のプロパティを使うことを真剣に考えています。幸運をお楽しみください! –

    関連する問題