カスケード– 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 Set stockDailyRecords =
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 Set stockDailyRecords =
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カスケードアノテーション間の互換性のない問題のように見えますが、その間の誤解の原因は何ですか?