I wrote a custom constraint which allows me to do queries against hibernate. This is helpful to detecting duplicates in the database and that sort of thing, and doing it declaratively and quickly.
Here is an example:
Code:
@QueryConstraint(
hql = "select count(*) from UserAccount where emailAddress = :emailAddress and id != :id",
message = "{userAccount.email.unique}" )
The idea is that if the query returns 0, then all is well... and if the query returns 1 or more results, then there is a validation problem.
Now, conceptually this is really nice (for me anyway). I am a little worried about the long-term use of this constraint. Will it cause problems with sessions? Will not going through spring's transaction layer create problems?
My validator looks like this:
Code:
public class QueryConstraintValidator implements ConstraintValidator<QueryConstraint,DomainObject> {
private String hql;
public void initialize( QueryConstraint queryConstraint ) {
this.hql = queryConstraint.hql();
}
public boolean isValid( DomainObject domainObject, ConstraintValidatorContext context ) {
BeanWrapper beanWrapper = new BeanWrapperImpl( domainObject );
SessionFactory sessionFactory =
( SessionFactory ) ApplicationContextProvider.getBean( "sessionFactory" );
if( sessionFactory != null ) {
StatelessSession statelessSession = sessionFactory.openStatelessSession();
Query query = statelessSession.createQuery(
HqlParser.removePeriodsFromParameterNames( hql )
);
for( String parameterName : HqlParser.getParameterNames( hql ) ) {
query.setParameter(
HqlParser.removePeriodsFromParameterName( parameterName ),
beanWrapper.getPropertyValue( parameterName )
);
}
boolean result = (Long) query.uniqueResult() == 0;
statelessSession.close();
return result;
}
return true;
}
I get a stateless session, because that works and I guess it has low risk associated with it. I be sure to close it once I'm done making the query.
Try and disregard all that stuff about HqlParser.*... that's just parsing the query so we can get the property values to use as parameters. I have to fix up the names a bit since doing stuff like "myObject.property = :myObject.property" will cause hibernate to bomb if that is used as a parameter name. Hibernate really just wants "myObject.property = :myObjectProperty" - and that works just fine. That's really all HqlParser is doing here... as well as parsing the string for all the property names in a nice convenient list.
So are there any dangers to what I am doing? Or is this safe?