私はまだ hibernate/hql を学習中ですが、半分はベスト プラクティスの質問、半分はサニティ チェックという質問があります。
クラスAがあるとしましょう:
@Entity
public class A
{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
@Column(unique=true)
private String name = "";
//getters, setters, etc. omitted for brevity
}
保存される A のすべてのインスタンスに一意の名前 (したがって @Column アノテーション) を付けるように強制したいのですが、その名前を持つ A インスタンスが既に保存されている場合も処理できるようにしたいと考えています。これを行うには2つの方法があります。
1) session.saveOrUpdate() 呼び出し中にスローされる可能性のある org.hibernate.exception.ConstraintViolationException をキャッチして、処理を試みることができます。
2) session.saveOrUpdate() を呼び出す前に、DAO で既にその名前を持つ A の既存のインスタンスを照会できます。
アプローチ1では、違反した制約をプログラムで把握する方法がわからないため、現在、アプローチ2に傾いています(Aには他にもいくつかの一意のメンバーがあります)。現在、私の DAO.save() コードはおおよそ次のようになっています。
public void save(A a) throws DataAccessException, NonUniqueNameException
{
Session session = sessionFactory.getCurrentSession();
try
{
session.beginTransaction();
Query query = null;
//if id isn't null, make sure we don't count this object as a duplicate
if(obj.getId() == null)
{
query = session.createQuery("select count(a) from A a where a.name = :name").setParameter("name", obj.getName());
}
else
{
query = session.createQuery("select count(a) from A a where a.name = :name " +
"and a.id != :id").setParameter("name", obj.getName()).setParameter("name", obj.getName());
}
Long numNameDuplicates = (Long)query.uniqueResult();
if(numNameDuplicates > 0)
throw new NonUniqueNameException();
session.saveOrUpdate(a);
session.getTransaction().commit();
}
catch(RuntimeException e)
{
session.getTransaction().rollback();
throw new DataAccessException(e); //my own class
}
}
私はこれを正しい方法で行っていますか?hibernate は、一意性制約に違反している値をプログラムで (つまり、エラー文字列としてではなく) 教えてくれますか? クエリをコミットから分離することで、スレッド セーフ エラーを招きますか?それとも安全でしょうか? これは通常どのように行われますか?
ありがとう!