2010-11-30 49 views
0

シーケンス番号を持つ混血代理キー:JPA、外部キーと私は2つのテーブルを持っている

DOCUMENT 
-------- 
DOC_ID (PK) 
. 
. 
. 

SECTION 
------- 
DOC_ID (FK, PK) 
SECTION_NUM (PK) 
. 
. 
. 

データベースのエントリは次のようになります。

ドキュメント:

DOC_ID | . . . 
-------------- 
1  | . . . 
2  | . . . 

セクション:

DOC_ID | SECTION_NUM | . . . 
--------------------------- 
1  | 1   | . . . 
1  | 2   | . . . 
1  | 3   | . . . 
2  | 1   | . . . 

DocumentにはDOC_IDで生成されたIdがあり、SectionにはDOC_IDとSECTION_NUMで合成された主キーがあります。

SECTION_NUMは、すべてのドキュメントに対して新しく開始するローカル(アプリケーション)生成シーケンス番号です。次のように

私のエンティティクラスは、見て:新しいドキュメントおよび関連セクションを挿入する際

@Entity 
@Table(name = "DOCUMENT") 
public class Document implements java.io.Serializable { 
    @Id 
    @Column(name = "DOC_ID", nullable = false) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "DocIdSeq") 
    @SequenceGenerator(name = "DocIdSeq", sequenceName = "DOC_ID_SEQ", allocationSize = 1) 
    private Long docId; 
} 


@Entity 
@Table(name = "SECTION") 
@IdClass(SectionId.class) 
public class Section implements java.io.Serializable { 
    @Id 
    @Column(name = "DOC_ID", nullable = false) 
    private Long docId; 

    @Id 
    @Column(name = "SECTION_NUM", nullable = false) 
    private Integer sectionNum; 

    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "DOC_ID") 
    private Document document; 
} 

public class SectionId implements java.io.Serializable { 
    private Long docId; 
    private Integer sectionNum; 
} 

、私は次の操作を行います

Document doc = new Document(); 

Section section = new Section(); 
section.setDocument(doc); 
section.setSectionNum(1); 

entityManager.persist(doc); 

私はNULLを述べる例外を取得持続することはできません列SECTION_NUMに許可されています。 私はOpenEJB(ユニットテストのために舞台裏でOpenJPAを使用しています)を使用しています.OpenJPAコードをステップ実行するとDocumentオブジェクトが正常に存続することがわかりましたが、Sectionオブジェクトになると反映され、すべてのフィールドがnullになるため、以前に保持されたDocumentオブジェクトにリンクする前にsectionNum値を失います。

残念ながら、DBスキーマを変更することはできません。これは従来のシステムです。 誰かが似たようなことをしていて、それが機能していますか?

答えて

0

私はいくつかの時間のためにこれを更新するために意味してきたが、あまりにも忙しかった...

[OK]を、ので、これはJPAと本当に不可能です判明。 ただし、回避策があります。

以前は、Documentクラスがこのようになっていると述べました。

@Entity 
@Table(name = "DOCUMENT") 
public class Document implements java.io.Serializable { 
    @Id 
    @Column(name = "DOC_ID", nullable = false) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = 
    "DocIdSeq") 
    @SequenceGenerator(name = "DocIdSeq", sequenceName = "DOC_ID_SEQ", allocationSize = 1) 
    private Long docId; 
} 

これは、この問題を明確にするための短縮バージョンです。 は、実際のクラスは、あまりにセクションのコレクションを持っています。セクションは、単純な主キーを持っていた場合

@Entity 
@Table(name = "DOCUMENT") 
public class Document implements java.io.Serializable { 
    @Id 
    @Column(name = "DOC_ID", nullable = false) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = 
"DocIdSeq") 
    @SequenceGenerator(name = "DocIdSeq", sequenceName = "DOC_ID_SEQ", allocationSize = 1) 
    private Long docId; 

    @OneToMany 
    private Set<Section> sections = new HashSet<Section>(0); 
} 

、JPAは簡単、それはアプリケーションからIDを受け入れるだろうと、関係を処理し、またはシーケンスからそれを生成するであろう、 1つのIDで両方を行うことはできません。

ので、解決策は、関係を自分で管理し、ライフサイクル機能を追加することです:あなたが見ることができるように

@Entity 
@Table(name = "DOCUMENT") 
public class Document implements java.io.Serializable { 
    @Id 
    @Column(name = "DOC_ID", nullable = false) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = 
    "DocIdSeq") 
    @SequenceGenerator(name = "DocIdSeq", sequenceName = "DOC_ID_SEQ", allocationSize = 1) 
    private Long docId; 

    @Transient 
    private Set<Section> sections = new HashSet<Section>(0); 

    @PostPersist 
    public void updateChildIds() { 
     for (Section section : this.sections) { 
      section.getId().setDocId(this.docId); 
     } 
    } 
} 

を、節の関係は、JPAがそれを管理しません意味、今一時的です。 Documentを永続化した後、フレームワークはupdateChildIds関数を呼び出します。ここでは、セクションIDを新しく永続化されたDocument IDで手動で更新します。

この

は、次のファサードに実証することができ:

@Stateless 
public void DocumentFacade implements DocumentFacadeLocal { 

    @PersistenceContext 
    private EntityManager entityManager; 

    public void save(Document entity) throws Exception { 
     this.entityManager.persist(entity); 
     this.entityManager.flush(); 
     this.persistTransientEntities(entity); 
     this.entityManager.flush(); 
    } 

    private void persistTransientEntities(CaseInstructionSheet entity) { 
     for (Section section : entity.getSections()) { 
      this.entityManager.persist(section); 
     } 
    } 
} 
0

実際には、JPAは完全にこれを処理することができます。あなたが探している注釈はMapsIdです。

@MapsId("docId") 

MapsId注釈の値は、この場合、あなたの複合主キー(これの属性名です:docIdあなたは、単に以下を追加する必要がある上、あなたのSectionで、あなたのケースで

、同じです)

+0

私の場合、@MapsIdが役に立つかもしれないと思いますか? https://stackoverflow.com/questions/46159867/オリジナルポスターの主な違いは、ManyToOneの代わりにOneToOneを使用することです。 – gouessej

関連する問題