古い Web アプリケーションを置き換えるために、JPA に基づく新しい Web アプリケーションを作成しています。移行の一環として、古いアプリケーションのデータベースを新しい、より洗練された JPA 管理のデータベースに変換しています。
そこで、古いデータベースを一連の JPA エンティティに変換し、その後それらを保存する「スクリプト」を作成しました。それはこのように動作します:
- ドメイン モデルの依存関係に基づいて変換順序を作成する
- エンティティごとに
- レガシー DB に対してデータベース クエリを実行する
- 取得した各テーブル行の新しいオブジェクトをメモリ内のリストに格納します
- 変換と同じ順序で生成されたリストを反復処理し、各エンティティを永続化します。
これで、最初の 2 つのステップがうまく機能します。ただし、永続化すると例外が発生します。例外は、あるエンティティが別のエンティティと関係を持っている場合に発生します。たとえば、エンティティの 1 つが でBook
、別のエンティティが との関係をChapter
定義しているとします。章を永続化すると、例外がスローされます。@ManyToOne(optional=false)
Book
java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation: models.Chapter.book -> models.Book
もちろん、これは本の状態に何か問題があることを示しています。設定されていないか、まだ永続化されていないようです。ただし、Book
の変換で が適切に設定されていることを確認できます。また、タイプのエンティティが永続化される前に、Chapter
タイプのすべてのエンティティが によって永続化されていることも確認できます。明らかに、私の JPA プロバイダーは期待どおりに動作せず、なんらかの理由でオブジェクトを完全に保持しません。Book
EntityManager
Chapter
Book
データベースに変換したオブジェクトのグラフ全体を保存するには、どのようなソリューションが必要ですか? JPA プロバイダーとして Hibernate を使用し、Spring 3.1 を使用して依存関係とEntityManager
s を注入します。
編集 1: いくつかの追加情報:チャプターで entityManager.persist() が呼び出される前に、各ブック オブジェクトで entityManager.persist() が呼び出されることを再度確認しました。ただし、book オブジェクトの id は null のままであり、適切に永続化されていません。トランザクションを使用していないにもかかわらず、データベースも空のままです。
編集 2: 上記のテキストからは明らかではないと思うため: 本と章のストーリーは単なる例です。別のエンティティを参照するすべてのエンティティで発生します。これにより、エンティティの値を適切に設定していないのではなく、JPA/Hibernate を適切に使用していないように見えます。
EDIT 3: 核となる問題は、 Book を適切に保持し、すべての適切な注釈を持っているにもかかわらず、book.getId() が null のままであることです。基本的に、Hibernate はエンティティを永続化した後にエンティティに ID を設定しないため、後でそれらのエンティティを使用する必要があるときに問題が発生します。