次のように@Cascade(CascadeType.SAVE_UPDATE)と@OneToManyの関係がある場合
public class One {
private Integer id;
private List<Many> manyList = new ArrayList<Many>();
@Id
@GeneratedValue
public Integer getId() {
return this.id;
}
@OneToMany
@JoinColumn(name="ONE_ID", updateable=false, nullable=false)
@Cascade(CascadeType.SAVE_UPDATE)
public List<Many> getManyList() {
return this.manyList;
}
}
そして多くのクラス
public class Many {
private Integer id;
/**
* required no-arg constructor
*/
public Many() {}
public Many(Integer uniqueId) {
this.id = uniqueId
}
/**
* Without @GeneratedValue annotation
* Hibernate will use assigned Strategy
*/
@Id
public Integer getId() {
return this.id;
}
}
私が持っている場合次のシナリオ
One one = new One();
/**
* generateUniqueId method will Take care of assigning unique id for each Many instance
*/
one.getManyList().add(new Many(generateUniqueId()));
one.getManyList().add(new Many(generateUniqueId()));
one.getManyList().add(new Many(generateUniqueId()));
one.getManyList().add(new Many(generateUniqueId()));
そして私は電話します
sessionFactory.getCurrentSession().save(one);
先に進む前に
推移的永続性Hibernateリファレンスドキュメントによると、次のように表示されます。
親がsave()、update()、またはsaveOrUpdate()に渡されると、すべての子がsaveOrUpdate()に渡されます。
わかった。それでは、Java PersistenceWithHibernateの本がsaveOrUpdateメソッドについてどのように語っているのか見てみましょう。
Hibernateは指定されたIDについてMANYテーブルにクエリを実行し、見つかった場合、Hibernateは行を更新します。見つからない場合は、新しい行を挿入する必要があります。
に従って翻訳することができます
INSERT INTO ONE (ID) VALUES (?)
/**
* I have four Many instances added To One instance
* So four select-before-saving
*
* I DO NOT NEED select-before-saving
* Because i know i have a Fresh Transient instance
*/
SELECT * FROM MANY WHERE MANY.ID = ?
SELECT * FROM MANY WHERE MANY.ID = ?
SELECT * FROM MANY WHERE MANY.ID = ?
SELECT * FROM MANY WHERE MANY.ID = ?
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?)
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?)
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?)
INSERT INTO MANY (ID, ONE_ID) VALUES (?, ?)
保存前の選択を回避するための回避策??? はい、どちらでもかまいません
- @Version列を追加します(適用されません)
- Hibernateインターセプターによって提供されるisTransientメソッドを実装します(私が持っているオプション)
したがって、この種のカスケードを使用するときにデフォルトの動作を保存する前に選択することを回避する方法として、トランザクションがSpringによって管理されるHibernateセッションにHibernateインターセプターを割り当てることでコードを改善しました。
これが私のリポジトリです
以前(Hibernateインターセプターなし):正常に動作します!
@Repository
public class SomeEntityRepository extends AbstractRepository<SomeEntity, Integer> {
@Autowired
private SessionFactory sessionFactory;
@Override
public void add(SomeEntity instance) {
sessionFactory.getCurrentSession().save(instance);
}
}
後(Hibernate Inteceptorを使用):問題が発生しました(SQLクエリは実行されません-INSERTもSELECT-BEFORE-SAVINGも実行されません)
@Repository
public class SomeEntityRepository extends AbstractRepository<SomeEntity, Integer> {
@Autowired
private SessionFactory sessionFactory;
@Override
public void add(SomeEntity instance) {
sessionFactory.openSession(new EmptyInterceptor() {
/**
* To avoid select-before-saving
*/
@Override
public Boolean isTransient(Object o) {
return true;
}
}).save(instance);
}
}
私の質問は、Hibernate Interceptorを使用しているときにSpringがエンティティとその関係を保持しないのはなぜですか?また、正常に機能するための回避策として何をすべきですか?