0

私は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           | . . .

DocumentDOC_ID に生成された Id があり、SectionDOC_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);

永続化すると、列 SECTION_NUM に NULL は許可されていないという例外が発生します。私は OpenEJB (単体テストのために舞台裏で OpenJPA に依存している) を使用しており、OpenJPA コードをステップ実行すると、Document オブジェクトが正常に永続化されることがわかりましたが、Section オブジェクトになると、新しいインスタンスが反射的に作成され、すべてが設定されます。 fields が null に設定されるため、sectionNum の値が失われ、Document オブジェクトにリンクする前に保持されます。

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

4

2 に答える 2

0

実際、JPA はこれを完全に処理できます。お探しの注釈は ですMapsId

あなたの場合、あなたSectionの にdocId、次を追加するだけです:

@MapsId("docId")

注釈の値は、MapsId複合主キーの属性名です (この場合は同じです)。

于 2013-06-21T19:09:32.590 に答える
0

久々に更新したかったのですが、忙しくて…

わかりました、これは 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);
}

Section に単純な主キーがある場合、JPA はアプリケーションから ID を受け入れるか、シーケンスから 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 はそれを管理しません。ドキュメントを永続化した後、フレームワークは updateChildIds 関数を呼び出します。ここで、新しく永続化されたドキュメント ID でセクション 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);
        }
    }
}
于 2010-12-29T03:03:35.697 に答える