Reputation: 1105
I made a custom @UniqueNombre validator to check if an user name already exists in the database and, when it is not repeated and tries to persist the data it throws an Hibernate exception:
ERROR org.hibernate.AssertionFailure - HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: null id in es.cesga.cloudpyme2.openinnovation.Usuario entry (don't flush the Session after an exception occurs)
The code of the validator is:
public class UniqueNombreValidator implements ConstraintValidator<UniqueNombre, String> {
@Override
public void initialize(UniqueNombre paramA) {
}
@Override
public boolean isValid(String nombre, ConstraintValidatorContext ctx) {
return (Usuario.countFindUsuariosByNombreEquals(nombre) == 0);
}
}
And the controller:
@RequestMapping(method = RequestMethod.POST, produces = "text/html")
public String create(@Valid Usuario usuario, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
if (bindingResult.hasErrors()) {
populateEditForm(uiModel, usuario);
return "usuario/create";
}
uiModel.asMap().clear();
setUpUsuario(usuario, httpServletRequest);
usuario.persist();
return "redirect:/usuario/" + encodeUrlPathSegment(usuario.getIdUsuario().toString(), httpServletRequest);
}
Without the check for a repeated user name, the controller works like charm. Any ideas?
UPDATE: Here is the method that is used inside the validator:
public static Long Usuario.countFindUsuariosByNombreEquals(String nombre) {
if (nombre == null || nombre.length() == 0) throw new IllegalArgumentException("The nombre argument is required");
EntityManager em = Usuario.entityManager();
TypedQuery q = em.createQuery("SELECT COUNT(o) FROM Usuario AS o WHERE o.nombre = :nombre", Long.class);
q.setParameter("nombre", nombre);
return ((Long) q.getSingleResult());
}
Upvotes: 0
Views: 686
Reputation: 13471
Have to be a custom for any reason?. Cannot use just a unique constrain?. You can put or in your script or as annotation
@Column(name = "usuario",unique=true)
String usuario;
Upvotes: 0
Reputation: 148965
I cannot be sure without the full stacktrace, but it looks like you are trying to use the EntityManager
outside of a transaction. It is declared static in the Usuario
class, and called through a static method. But unless you declared a transaction in your controller (which would be uncommon), none is opened when you call em.createQuery(...)
, so Hibernate throws an exception.
As you only do readonly operation, a simple workaround is to use the open session in view pattern with an OpenSessionInViewFilter
. It allows for a (normally readonly) session to be disponible all along a request processing.
Upvotes: 2
Reputation: 153800
I think your validator fires before the entity has been assigned a proper identifier value, hence the exception you got.
I wouldn't recommend running queries in validators. That type of rules are always better enforced by the database anyway. Your application logic should try to avoid such scenarios therefore a first step is to run the query prior to saving the data.
An exception should be reported to the user as fast as possible to prevent further actions that might be lost by a failing transactions. Once the session has thrown an exception you may no longer use it, as it may be in an inconsistent state anyway.
Upvotes: 0