カスケード - JPA

カスケード– 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_PERSISTACTION_MERGEを渡し、一致せず、カスケードの実行に失敗します。

@seeソースコード

  • org.hibernate.engine.Cascade

  • org.hibernate.engine.CascadeStyle

  • org.hibernate.engine.CascadingAction

溶液

JPAカスケード–javax.persistence.CascadeTypeを削除し、Hibernateカスケード–org.hibernate.annotations.CascadeCascadeType.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カスケードアノテーション間の互換性のない問題のように見えますが、その間の誤解の原因は何ですか?