2

JPA アノテーションを使用して Hibernate でシリアル化する小さなデータ構造データ構造があります。

(以下は非常に単純化されています)

public class Result {
   @Id
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   public int id;


   @OneToMany(cascade=CascadeType.ALL)
   @OrderColumn("row")
   @JoinColumn("ResultId)
   public List<Row> rows
}

public class Row {
   @Id
   @GeneratedValue(strategy=GenerationType.IDENTITY)
   public int id;

   @ElementCollection
   @OrderColumn("col")
   public List<Double> value;
}

結果を取得しようとするとpersist()、TransientObjectException が発生します。それはどうしてですか?cascade=ALL でこれを処理するべきではありませんか?

4

1 に答える 1

2

結局のところ、Hibernate と Guava (Google Collections) の間でかなりの相互作用に遭遇しました。実際、Guava のこの 1 つの機能は、より明確に発表する必要があります。

私の質問のコード サンプルは不完全でした。Result関連する(および欠落している)詳細は、パラメーターとして受け取るコンストラクターがあったという事実でしたList<List<Double>>。これは、アプリの残りの部分にとってより自然です。

残念ながら、Hibernate は 2 次元配列の保存が得意ではないため、このRowクラスは簡単な回避策でした。

残りのコードとのインターフェースを維持するために、Guava から- 他に - を使用して、コンストラクターでList<List<>>toに変換します。List<Row>Lists.transform

結果のオブジェクトを DB に保存しようとすると、Hibernate から例外が発生しました。

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: <my class here>

もう少し深くデバッグしたところ、RowオブジェクトがsetId呼び出されたのは、呼び出された行オブジェクトではないことがgetIdわかりました (getter と setter がありました - 私のコード サンプルのもう 1 つの簡略化)。

それからそれは私に夜明けをもたらしました。コピーではなく、基になるリストのビューtransform()を生成します。変換されたオブジェクトを要求するたびに、ゼロから作成され、新しい「id」フィールドが 0 に初期化されます。

これを教訓にしましょう: 変換が余分な状態の可能性を追加する場合は、Guava のLists.transformドキュメントの提案に従ってください:

返されたリストがビューである必要がない場合に遅延評価を回避するには、返されたリストを選択した新しいリストにコピーします。

于 2013-08-23T18:10:23.387 に答える