Todavía estoy en el proceso de aprender hibernate/hql y tengo una pregunta que es mitad de prácticas recomendadas/comprobación de cordura media.hibernate column uniqueness question
Digamos que tengo una clase 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
}
Quiero hacer cumplir que cada caso de A que es salvado tiene un nombre único (de ahí la anotación @Column), pero también quiero ser capaz para manejar el caso donde ya hay una instancia A guardada que tiene ese nombre. Veo dos formas de hacer esto:
1) Puedo capturar la org.hibernate.exception.ConstraintViolationException que podría lanzarse durante la llamada a session.saveOrUpdate() e intentar manejarlo.
2) Puedo consultar las instancias existentes de A que ya tienen ese nombre en el DAO antes de llamar a session.saveOrUpdate().
Ahora me estoy inclinando por el enfoque 2, porque en el enfoque 1 no sé cómo averiguar programáticamente qué restricción se violó (hay un par de otros miembros únicos en A). Ahora mismo mi DAO.save código() se ve más o menos así:
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
}
}
¿Voy sobre esto en el camino correcto? ¿Puede Hibernate decirme programáticamente (es decir, no como una cadena de error) qué valor está violando la restricción de exclusividad? Al separar la consulta de la confirmación, ¿estoy invitando errores de seguridad de subprocesos o estoy a salvo? ¿Cómo se hace esto usualmente?
Gracias!
¿Tendré algún problema de seguridad con el segundo enfoque? Por lo que yo entiendo, la parte de "Aislamiento" de los principios de ACID DB se supone que me ayuda aquí, pero no estoy seguro de cuán compatible hibernate/hsqldb con eso. – Seth
No entiendo por qué el aislamiento es importante para este caso. Probar si un nombre existe ocurriría en la misma transacción y no altera el estado de los datos en la base de datos. – Rachel