Showing posts with label hibernate. Show all posts
Showing posts with label hibernate. Show all posts

Tuesday, 14 June 2011

Two nice Groovy design patterns

Putting my deep SQL and HSQL roots on hold I took advantage of Hibernate Criteria (via the excellent Groovy builder for super readable code) to safely generate a dynamic query today. I stumbled into two problems:
  1. how to keep things DRY - can I avoid rewriting the same query multiple times when simple things change?
  2. how can I elegantly query associations whose names I do not know in advance?
I was able to resolve both issues quite satisfactory.

Keeping queries DRY

My first attempt was to create a basic query structure as a Groovy closure and then modify it at runtime as the exact query would be known. Couldn't make it work. Fortunately, the second attempt was more successful: I used a simple factory pattern to create the closure dynamically before feeding it into the Criteria Builder:
def createQuery = { Boolean discriminate ->
	 return {
	 	 projections {
	 	 	 sum "property"
	 	 }
	 	 if (discriminate) {
	 	 	 idEq 42
	 	 }
	 }
}
MyClass.createCriteria().list(createQuery(false))

Choosing associations dynamically

In order to reference an association, you have to use its name in the closure as a method call with a closure as the parameter. Suppose you have the name of the property in a string object, how do you call it as a method in the closure ? Using evals could've worked, but that would present a serious security risk. Groovy's GStrings to the rescue:
def discriminateProp = params.prop
def discriminateBy = params.val
def createQuery = { Boolean discriminate ->
	 return {
	 	 projections {
	 	 	 sum "property"
	 	 }
	 	 if (discriminate) {
	 	 	 "${discriminateProp}" {
	 	 	 	 	 idEq discriminateBy.toLong()
	 	 	 }
	 	 }
	 }
}
MyClass.createCriteria().list(createQuery(true))
I still have to wrap my brains around possible security risks of this approach, but at the first glance it seems solid.