20

JPAを使用して、データベースからいくつかのものをロードしています。一部のエンティティは、それらの間にオプションの関係を持つ場合があります。

@Entity
public class First {
    ....
    @OneToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
    @JoinColumns(value = {
        JoinColumn(name = "A_ID", referencedColumnName = "A_ID", insertable = false, updatable = false), 
        JoinColumn(name = "B_ID", referencedColumnName = "B_ID", insertable = false, updatable = false)})
    private Second second;

この関連付けがデータベースに存在する場合、すべてが正常に機能しています。そうでないjavax.persistence.EntityNotFoundException
場合、関連付けが存在しない場合に、このフィールドを NULL にするという例外が必要です。

いくつかの異なることを試しました。たとえば、関係注釈で optional=true を使用したり (これはデフォルトのオプションです)、Nullable として配置したりしました。何もうまくいかないようです。これらのオプションはすべて無視されているようです。

これとまったく同じ問題(およびスタックオーバーフローのいくつかの質問)に言及しているリンクがたくさん見つかりましたが、それらのすべてで、@NotFoundHibernate の注釈を使用することをお勧めします。しかし、Hibernate に依存する必要はありません (すべてを純粋な JPA に保ちたいと考えています)。

これを解決する他の方法を知っている人はいますか?

ご協力ありがとうございました。

4

6 に答える 6

7

以下は、この問題の代替ソリューションです。リレーションが壊れていることがある古いデータベースの上に構築する必要がありました。これが、JPAのみを使用して解決した方法です。

@PostLoad
public void postLoad(){
    try {
        if(getObject() != null && getObject().getId() == 0){
            setObject(null);
        }
    }
    catch (EntityNotFoundException e){
        setObject(null);
    }
} 
于 2013-10-23T13:42:56.533 に答える
2

optional = trueパラメータを@OneToOne注釈に追加してみてください。

于 2012-09-04T17:35:26.357 に答える
2

私は同じ問題に遭遇しました。常に再現できるとは限らないため、テストすることはできませんが、いくつかの考えを次に示します。

  1. Second クラスのインスタンスは削除されますが、First クラスのインスタンスはそれについて何も知りません。
  2. Second のインスタンスが削除されたときに、First のインスタンスに通知する方法が必要です。
  3. ここでは、削除するためのカスケード オプションは役に立ちません。
  4. First のインスタンスが Second のインスタンス内に存在する場合、双方向の関係を使用することができます。Second を削除する前に Second のインスタンスを介して First のインスタンスを更新できます
  5. 双方向の関係 - 悪です。あなたの場合、First - は Second の所有者だと思います。2 番目のインスタンスを直接削除するサービスを許可しないでください。First のインスタンスで動作するサービスは、Second のインスタンスを削除します。この場合、EntityManager を介して Second のインスタンスを削除するよりも、最初に「second」フィールドを null 可能にすることができます。
  6. クエリを実行し、第 2 レベルのキャッシュが有効で、クエリに結果をキャッシュできるヒントがある場合、例外が発生する場合があります。次の方法でクエリの結果を取得することをお勧めします。
private List<?> getQueryResult(final Query query)
{
    try
    {
        return query.getResultList();
    }
    catch (EntityNotFoundException e)
    {
        return query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH).getResultList();
    }
}
  1. クエリではなく EntityManger を介してエンティティを操作し、エンティティがキャッシュされているために例外が発生した場合、Second を削除するとキャッシュ内の First のすべてのエンティティが無効になる可能性があります。

私はそれをテストすることができず、それを機能させることができないので、この解決策について議論したいと思います。誰かが試したら、私に知らせてください。

PS: 誰かがこの問題を再現する休止状態の単体テストを持っている場合は、お知らせください。詳しく調べてみたいと思います。

于 2015-04-17T08:45:50.090 に答える
0

コレスポンデント エンティティ クラスにテストを追加するのはどうでしょうか。

public boolean getHasSecond() {
    if (this.Second != null) {
        return true;
    } else {
        return false;
    }
}

このように、関係が存在するかどうかを確認できます...

于 2012-09-04T11:33:34.430 に答える
-2

cascade=CascadeType.ALL@OneToMay(*****) で使ってみてください。

于 2020-07-07T08:50:54.640 に答える