views:

173

answers:

3

We have an application which needs to detect duplicates in certain fields on create. We are using Hibernate as our persistence layer and using Spring's HibernateTemplate. My question is whether it is better to do so an upfront lookup for the item before creating, or to attempt to catch the DataIntegrityViolation exception and then check if this is caused by a duplicate entry.

+4  A: 

It depends on whether having a duplicate is an exceptional scenario, or a business-logic case.
For example, checking for unique email/username during registration is a business-logic case and the check should be done before trying to insert

If you are required to indicate which field exactly has failed with the unique constraint, you'd better check it beforehand, rather than catching the exception. Catching the exception doesn't give you the important detail - which field has failed.

There are ways to obtain this information, based on the exception, but it is very tedious and is database-specific (lookup the constraint name in the DB (db-specific), get the field it is applied on, match the field with the entity property)

Bozho
A: 

Hi Dean, i definitely go with Bozho answer. I think this is exactly the point.
There is a similar problem within the project i am currently working on. We are sharing informations between multiple servers based on filters and there can be scenarios where received objects already have been added to database so a PK exception would occur.

In our case these PK conflicts are very rare and so we consider this situation as exceptional. We are also using spring and hibernate and in order to seperate these concerns and due to Springs Transaction-Definitions we are using AOP to catch the specific DataIntegrity-Exception and rerun the Transaction doing the needed integrity checks on demand.
I could elaborate on this if you need help using the ExceptionHandlerAdvice.

zoidbeck
+1  A: 

It is better to check if data is present in the database. One easy way to check if the data already exists in the database is to have your classes implement Hibernate LifeCyle api. Hibernate allows you to do validate behavior before saving but after an identity is associated with the bean. If certain logic is violated or fails, then save operation can be vetoed.

public class Bean extends Serializable implements org.hibernate.classic.LifeCycle {
      public boolean onSave(Session s) {
          Query query = session.createQuery(from Bean b where b.field=:field");
          query.setParameters("field", this.field);
          @SuppressWarnings("unchecked")
          List<Bean> beans = query.list();
          if (beans != null && !beans.isEmpty()) {
              // This does not save the identity.
              return VETO;
          }
          return NO_VETO;
      }
}
Kartik