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:
- how to keep things DRY - can I avoid rewriting the same query multiple times when simple things change?
- 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.
No comments:
Post a Comment