0

古い W​​eb アプリケーションを置き換えるために、JPA に基づく新しい Web アプリケーションを作成しています。移行の一環として、古いアプリケーションのデータベースを新しい、より洗練された JPA 管理のデータベースに変換しています。

そこで、古いデータベースを一連の JPA エンティティに変換し、その後それらを保存する「スクリプト」を作成しました。それはこのように動作します:

  1. ドメイン モデルの依存関係に基づいて変換順序を作成する
  2. エンティティごとに
    1. レガシー DB に対してデータベース クエリを実行する
    2. 取得した各テーブル行の新しいオブジェクトをメモリ内のリストに格納します
  3. 変換と同じ順序で生成されたリストを反復処理し、各エンティティを永続化します。

これで、最初の 2 つのステップがうまく機能します。ただし、永続化すると例外が発生します。例外は、あるエンティティが別のエンティティと関係を持っている場合に発生します。たとえば、エンティティの 1 つが でBook、別のエンティティが との関係をChapter定義しているとします。章を永続化すると、例外がスローされます。@ManyToOne(optional=false)Bookjava.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 プロバイダーは期待どおりに動作せず、なんらかの理由でオブジェクトを完全に保持しません。BookEntityManager ChapterBook

データベースに変換したオブジェクトのグラフ全体を保存するには、どのようなソリューションが必要ですか? JPA プロバイダーとして Hibernate を使用し、Spring 3.1 を使用して依存関係とEntityManagers を注入します。

編集 1: いくつかの追加情報:チャプターで entityManager.persist() が呼び出される前に、各ブック オブジェクトで entityManager.persist() が呼び出されることを再度確認しました。ただし、book オブジェクトの id は null のままであり、適切に永続化されていません。トランザクションを使用していないにもかかわらず、データベースも空のままです。

編集 2: 上記のテキストからは明らかではないと思うため: 本と章のストーリーは単なる例です。別のエンティティを参照するすべてのエンティティで発生します。これにより、エンティティの値を適切に設定していないのではなく、JPA/Hibernate を適切に使用していないように見えます。

EDIT 3: 核となる問題は、 Book を適切に保持し、すべての適切な注釈を持っているにもかかわらず、book.getId() が null のままであることです。基本的に、Hibernate はエンティティを永続化した後にエンティティに ID を設定しないため、後でそれらのエンティティを使用する必要があるときに問題が発生します。

4

4 に答える 4

3

私はかつて、休止状態からのこのようなエラーと戦ったことがあります。問題の原因は、オブジェクト グラフの円とカスケード設定の組み合わせであることが判明しました。

しばらく経っているため、ファウリングは 100% 正確ではないかもしれませんが、問題を追跡するのに十分な情報である可能性があります。

  1. Hibernateチャプターを挿入したい。最初に本を挿入する必要があることを認識します。
  2. を挿入したい。最初に別のエンティティを挿入する必要があることを認識します (例: publisher )
  3. 発行者を挿入し、発行者で定義されたカスケードを実行します (例: author )
  4. 著者は、たとえば、lastestBookへの参照を持っています。hibernate は内部的にすでにブックを処理済みとしてマークしているため (ステップ 2)、author.book が一時的なインスタンスを参照しているという例外は発生しません。

これがあなたの問題であるかどうかを調べるには、完全な休止状態のデバッグを有効にして、休止状態がオブジェクト グラフを通過するパスをたどることができます。

于 2013-01-19T18:32:21.817 に答える
0

user1888440 との話し合いのおかげで答えが見つかりました。

この回答に対する解決策は@Transactional、私のアプリケーションでは Spring アノテーションが機能しないことでした。これは、Hibernate が行ったすべてのことがトランザクションのコンテキストで発生したわけではないことを意味します。これは、永続化後に Hibernate が ID を設定しないことを意味し、これはすべての変換が失敗することを意味していました。

うまくいかなかった理由@Transactionalはおそらく、私が言及しなかった事実によるものです: このスクリプトは Play 2.0 (実際には 2.1) アプリの一部であり、SBT を使用して構築されています。SBT は、通常の Java セットアップを使用してアプリケーションを構築するのではなく、代わりに Scala コンパイラを使用して Java をコンパイルします。私の推測では、Scala コンパイルは、Spring が動作するために必要な AspectJ ではうまく動作しませんでした@Transactional

代わりに、プログラムで定義された Spring トランザクション(セクション 11.6)内で、この変換に関連するすべてのデータベース作業を実行しました。これで、すべてが期待どおりに動作します。

于 2013-01-19T21:42:37.317 に答える
0

hbm ファイルの主キー/オブジェクト ID の保存されていない値を確認してください。休止状態のフレームワークによって自動化された ID 作成があり、ID をどこかに設定している場合、このエラーがスローされます。デフォルトでは、保存されていない値は 0 です。 ID を 0 に設定すると、このエラーが表示されます。

于 2013-06-08T19:48:08.920 に答える
-1

永続化する前に、各章に本を割り当てるのを忘れているようです。Bookを永続化した場合でも、Chapterを永続化する前に、Chapterインスタンスの#bookプロパティに割り当てる必要があります。これは、関係を非オプションとして指定したためです。#bookがnullになることはありません。

于 2013-01-19T16:47:16.497 に答える