更新を保存するとき、hibernate noniqueObjectException
-
29-10-2019 - |
質問
私はこの簡単な状況を持っています:
@Entity
public class Customer{
@ManyToMany(fetch=FetchType.EAGER)
@Cascade(CascadeType.SAVE_UPDATE)
private List<Product> products=new ArrayList<Product>();
}
@Entity
public class Produtc{
@ManyToOne
@Cascade(CascadeType.SAVE_UPDATE)
private Category category;
}
@Entity
public class Category{
private String name;
}
新しい顧客を挿入するためのルーチン:
Customer customer=new Customer();
//customer.set data
Product p=dao.getProductBySomeUserInput...
if(p==null){
p=new Product();
//p.set data
}
customer.addProduct(p);
dao.save(customer); //this row throw NonUniqueObjectException on Category class
この問題を解決するにはどうすればよいですか?問題はcascadeType.save_updateに関連していると思いますが、必要なのは...ありがとうございます。
アップデート
私は問題を見つけました、そしてこれがそれを複製する方法です:
Customer c=new Customer();
// Load two products by id
Product p=dao.get(Product.class, 2);
Product p1=dao.get(Product.class, 3);
c.addProduct(p);
c.addProduct(p1);
// This try to update products, and category of products becouse CascadeType is SAVE_UDPATE
dao.save(c);
したがって、PとP 1に異なるカテゴリがある場合、Probsはありませんが、PとP1に同じカテゴリがある場合、同じカテゴリがセッション中であるため、カテゴリに非UniqueObjectExceptionがあり、Hibernateがその保存を試みます。
製品エンティティとカテゴリエンティティの両方でcascadeType.save_updateが必要です。この問題を解決するにはどうすればよいですか?ありがとう。
解決
問題はおそらく、トランザクション管理が悪いためです。すべてのコードは、DAOコールごとにトランザクションを使用するのではなく、単一のトランザクションで実行する必要があります。サービスレイヤーは、DAOレイヤーではなく、トランザクションを区別するものである必要があります。
私は冬眠が何をするか想像できます:
- あなたが呼ぶ
dao.get(Product.class, 2)
. 。これにより、ID 67(たとえば)のカテゴリを指すデタッチされた製品が返されます。 DAOへの呼び出しが終了すると、トランザクションが終了するため、結果は分離されます。 - あなたが呼ぶ
dao.get(Product.class, 3)
. 。これにより、ID 67(たとえば)のカテゴリを指すデタッチされた製品が返されます。ただし、コールは別のトランザクションで実行されるため、2番目の異なるカテゴリインスタンス(最初のIDと同じIDを使用)を取得します。 - 製品のSaveorUpDateを呼び出します。これはカテゴリにカスケードされるため、HibernateはCategory1とcategory2をセッションに添付する必要があります。どちらも同じIDを持っているため、カスケードの1つは行われない可能性があります。
単一のトランザクションを使用して両方の製品を取得すると、どちらも同じカテゴリインスタンスがあり、問題は発生しません。電話 merge
それ以外の saveOrUpdate
また、機能する必要があります。Hibernateは、両方のカテゴリの状態を3番目のカテゴリにコピーします。しかし、正しいことは、DAOへの両方の呼び出しを含むトランザクションを使用することです。
所属していません StackOverflow