カスケード– JPAおよびHibernateアノテーションのよくある間違い
多くの場合、開発者はJPAとHibernateアノテーションを一緒に使用しますが、それは非常に一般的な間違いを引き起こします。JPAカスケードタイプアノテーションはHibernateで機能しませんか?
コードレビューのセクションで、多くのJava開発者がこの間違いに気づいておらず、プログラムが関連エンティティへのカスケード操作を実行できなかったことがわかりました。 このone-to-many hibernate exampleをデモンストレーションに使用します。
間違い
1対多の例では、多くの開発者がJPAカスケードオプションを次のように宣言しました。
... @Entity @Table(name = "stock", catalog = "example", uniqueConstraints = { @UniqueConstraint(columnNames = "STOCK_NAME"), @UniqueConstraint(columnNames = "STOCK_CODE") }) public class Stock implements java.io.Serializable { ... private SetstockDailyRecords = new HashSet (0); @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST,CascadeType.MERGE }, mappedBy = "stock") public Set getStockDailyRecords() { return this.stockDailyRecords; } public void setStockDailyRecords(Set stockDailyRecords) { this.stockDailyRecords = stockDailyRecords; } ...
Hibernateセッションで保存します。
stockDailyRecords.setStock(stock); stock.getStockDailyRecords().add(stockDailyRecords); session.save(stock); session.getTransaction().commit();
コードが実行しようとしているのは、「在庫」を保存するとき、関連するstockDailyRecordsも保存することです。 すべて正常に見えますが、THIS IS NOT WORKINGの場合、カスケードオプションは実行されず、stockDailyRecordsが保存されません。 間違いを見つけられますか?
説明
コードを見てください。@OneToManyはJPAからのものであり、JPAカスケード–javax.persistence.CascadeTypeが必要です。 ただし、Hibernateセッションで保存すると、org.hibernate.engine.Cascadeは次のチェックを行います…
if ( style.doCascade( action ) ) { cascadeProperty( persister.getPropertyValue( parent, i, entityMode ), types[i], style, anything, false ); }
Hibernateの保存プロセスによりACTION_SAVE_UPDATEアクションが発生しますが、JPAはACTION_PERSISTとACTION_MERGEを渡し、一致せず、カスケードの実行に失敗します。
@seeソースコード
-
org.hibernate.engine.Cascade
-
org.hibernate.engine.CascadeStyle
-
org.hibernate.engine.CascadingAction
溶液
JPAカスケード–javax.persistence.CascadeTypeを削除し、Hibernateカスケード–org.hibernate.annotations.Cascade、CascadeType.SAVE_UPDATEに置き換えます。
... @Entity @Table(name = "stock", catalog = "example", uniqueConstraints = { @UniqueConstraint(columnNames = "STOCK_NAME"), @UniqueConstraint(columnNames = "STOCK_CODE") }) public class Stock implements java.io.Serializable { ... private SetstockDailyRecords = new HashSet (0); @OneToMany(fetch = FetchType.LAZY, mappedBy = "stock") @Cascade({CascadeType.SAVE_UPDATE}) public Set getStockDailyRecords() { return this.stockDailyRecords; } public void setStockDailyRecords(Set stockDailyRecords) { this.stockDailyRecords = stockDailyRecords; } ...
これで、期待どおりに機能します。
結論
HibernateがJPA実装である場合、JPAとHibernateカスケードアノテーション間の互換性のない問題のように見えますが、その間の誤解の原因は何ですか?