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にしたいのです。
私はいくつかの異なることを試しました。関係アノテーション(オプションはbtwがデフォルトのオプションです)でoptional = trueを使用し、それをNullableとして配置するなど。
私はこの非常に同じ問題(およびここStackoverflowのいくつかの質問)に言及する多くのリンクを見つけましたが、それらすべてで@NotFound
Hibernateからのアノテーション。ただし、Hibernateへの依存関係は必要ありません(すべてを純粋なJPAに保ちたい)。
これを解決する他の方法を知っている人はいますか?
ご協力ありがとうございます。
以下は、この問題の代替ソリューションです。関係が壊れることがある古いデータベースの上に構築する必要がありました。これが、JPAのみを使用して解決した方法です。
@PostLoad
public void postLoad(){
try {
if(getObject() != null && getObject().getId() == 0){
setObject(null);
}
}
catch (EntityNotFoundException e){
setObject(null);
}
}
関連するエンティティIDを削除すると発生します。私の場合、ブランドテーブルに応じて製品テーブルがありました。製品インスタンスの1つが依存していたブランドIDの行またはエンティティを削除しました。
同じ問題に遭遇しました。常に再現できるとは限らないため、テストすることはできませんが、いくつかの考えがあります。
- Secondクラスのインスタンスは削除されますが、Firstクラスのインスタンスはそれについて何も知りません。
- Secondのインスタンスが削除されたときに、Firstのインスタンスに通知する方法が必要です。
- 削除のカスケードオプションは、ここでは役に立ちません。
- FirstのインスタンスがSecondのインスタンス内に存在する場合は、双方向の関係を使用してみてください。 2番目を削除する前に、2番目のインスタンスを介して1番目のインスタンスを更新できます
- 双方向の関係-悪です。あなたのケースでは、FirstがSecondの所有者だと思います。サービスが2番目のインスタンスを直接削除することを許可しないでください。 Firstのインスタンスで機能するサービスに、Secondのインスタンスを削除させます。この場合、EntityManagerを介してSecondのインスタンスを削除するよりも、最初に「second」フィールドをnull可能にすることができます。
- クエリを実行し、2次キャッシュが有効になっていて、クエリにヒントがあり、その結果をキャッシュできる場合、例外が発生することがあります。次の方法でクエリの結果を取得できます。
private List<?> getQueryResult(final Query query)
{
try
{
return query.getResultList();
}
catch (EntityNotFoundException e)
{
return query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH).getResultList();
}
}
- EntityMangerを介してエンティティを操作し、クエリを介さずに、エンティティがキャッシュされているために例外が発生した場合、Secondを削除すると、キャッシュ内のFirstのすべてのエンティティが無効になることがあります。
私はそれをテストすることができず、それを機能させることができないので、この解決策について話したいと思います。誰かが試みたら、私に知らせてください。
PS:誰かがこの問題を再現するhibernateの単体テストを持っている場合は、お知らせください。さらに調査したいと思います。
OneToOneアノテーションにoptional = trueを追加してみてください。
対応するエンティティクラスにテストを追加する場合はどうでしょうか。
public boolean getHasSecond() {
if (this.Second != null) {
return true;
} else {
return false;
}
}
このように、関係が存在するかどうかを確認できます...