Result set mapping in Grails / GORM - grails

I want to map the result of a native SQL query to a simple bean in grails, similar to what the #SqlResultSetMapping annotation does.
For example, given a query
select x.foo, y.bar, z.baz from //etc...
map the result to
class FooBarBaz {
String foo
String bar
String baz
}
Can anyone provide an example of how to do this in grails?
Thanks in advance.

I tested this successfully in the Grails console
import groovy.sql.Sql
class FooBarBaz {
String foo
String bar
String baz
}
// Initialising the Sql object like this ensures that the SQL statement
// will participate in the current transaction (if one exists)
// 'ctx' refers to the Spring ApplicationContext when using the Grails console
def sessionFactory = ctx.getBean('sessionFactory')
Sql sql = new Sql(sessionFactory.currentSession.connection())
def query = 'select email, user_real_name, phone from user'
def results = []
sql.eachRow query, {row -> results << new FooBarBaz(foo: row.email, bar: row.user_real_name, baz: row.phone)}

Related

Groovy: Dynamic nested properties [duplicate]

I am wondering if I can pass variable to be evaluated as String inside gstring evaluation.
simplest example will be some thing like
def var ='person.lName'
def value = "${var}"
println(value)
I am looking to get output the value of lastName in the person instance. As a last resort I can use reflection, but wondering there should be some thing simpler in groovy, that I am not aware of.
Can you try:
def var = Eval.me( 'new Date()' )
In place of the first line in your example.
The Eval class is documented here
edit
I am guessing (from your updated question) that you have a person variable, and then people are passing in a String like person.lName , and you want to return the lName property of that class?
Can you try something like this using GroovyShell?
// Assuming we have a Person class
class Person {
String fName
String lName
}
// And a variable 'person' stored in the binding of the script
person = new Person( fName:'tim', lName:'yates' )
// And given a command string to execute
def commandString = 'person.lName'
GroovyShell shell = new GroovyShell( binding )
def result = shell.evaluate( commandString )
Or this, using direct string parsing and property access
// Assuming we have a Person class
class Person {
String fName
String lName
}
// And a variable 'person' stored in the binding of the script
person = new Person( fName:'tim', lName:'yates' )
// And given a command string to execute
def commandString = 'person.lName'
// Split the command string into a list based on '.', and inject starting with null
def result = commandString.split( /\./ ).inject( null ) { curr, prop ->
// if curr is null, then return the property from the binding
// Otherwise try to get the given property from the curr object
curr?."$prop" ?: binding[ prop ]
}

get a specific property for a domain in Grails

i'm making a tables cleaning service that takes the table name and the date field as arguments , here is the service code :
def cleanTables(tableName , dateField) {
def comparisonDate
def numOfRecordsDeleted
use (TimeCategory){
comparisonDate=new Date() -1.year
}
numOfRecordsDeleted=tableName.where { dateField <=comparisonDate }.deleteAll()
log.info("deleted : " +numOfRecordsDeleted)
}
i'm successfully passing to this service the table name but i can't pass the date field , so how to get a specific property from a domain for example a domain named Payments got a property dateCreated , so i pass to my service Payments and dateCreated.
With where queries you have access to criteria query methods such as eq(), or in this case, le(). Those methods take the name of the property as an argument, which is what you need. I tweaked the code a bit because you're actually interacting with domain classes, not tables. Small distinction, until you start working with HQL.
def cleanDomainClass(String domainClassName, String dateField) {
def domainClass = Class.forName("some.package.$domainClassName")
def comparisonDate = use (TimeCategory) { new Date() -1.year }
def numOfRecordsDeleted = domainClass.where { le(dateField, comparisonDate) }.deleteAll()
log.info("deleted : $numOfRecordsDeleted")
}

GORM where query on an embedded object

I have domain classes A and B as follows:
class A {
String prop1
String prop2
B prop3
static embedded = ['prop3']
}
class B {
String prop4
String prop5
}
When I want to query like this:
def q = A.where { prop3.prop4 == 'bla' }
def list = q.list()
I get the following exception:
Cannot get property 'javaClass' on null object. Stacktrace follows:
on the "def q = A.where ..." line.
Any clue what's the problem? I've checked this:
http://grails.1312388.n4.nabble.com/GORM-embedded-object-issue-td1379137.html
but how to "just call them directly" is not quite clear to me. Any other way of querying the embedded objects in GORM?
I finally gave up on the where query and went with the DetachedCriteria approach. Gives me the same flexibility as the where queries, but works with embedded domain objects:
def criteria = new DetachedCriteria(A).build {
eq 'prop1', 'bla2'
}
criteria = criteria.build {
eq 'prop3.prop4', 'bla'
}
def list = criteria.list()
What do you get if you do (assuming B is in src/groovy)
def q = A.where { prop3 == new B(prop4: 'bla') }
def list = q.list()
Embedded components are persisted inside the main domain class (owner) itself. It can be accessed directly using any dynamic finder as you do directly on a domain object.
The above can also be represented in dynamic finders as:
A.findAllByProp3(new B(prop4: 'bla'))

how to pass a list to the query in Groovy SQL?

I've a scenario to pass a List of char values to the query in Grails.
When I pass the List this is what happening
def accounts = ['A', 'B']
AND acct.account_status_cd in '${accounts}
the query looks like "AND acct.account_status_cd in '[A,B]'"
but it should be "AND acct.account_status_cd in ('A','B')"
how to achieve this?
Resolved it by Passing as a String...
String s = keys.collect { "'$it'" }.join( ',' )
It gives me S = 'A','B','C'
A solution could be a NamedQuery inside your domain class, something like this:
class Account {
// code omitted
static namedQueries = {
accountsInList { accountList ->
'in'("account_status_cd", accountList)
}
}
Then you can use this namedQuery like:
Account.accountsInList(['A', 'B']).list()
Ofcourse you can also use a withCriteria.
See the docs for more info:
http://grails.org/doc/2.2.x/ref/Domain%20Classes/createCriteria.html

Grails Gorm MongoDB index Embedded String Map

I wanted to make some translatable content with rest service so i decided to create collection with this structure. But I can't find BSON by value from String Map.
class LocalizableString{
static mapWith = "mongo"
ObjectId id
Map<String, String> values = new HashMap<String, String>();
}
Then i wanted to get like this. But it works like join query.
def list = LocalizableString.createCriteria().list {
values{ like('value',"%${value}%") }
}
Here is similar plain mongo example. But how can i implement it with gorm mongoDB http://www.mongodb.org/display/DOCS/Schema+Design#SchemaDesign-Example
Is there any solution for that ?
class BaseService {
def findByLocalizableString(def domainClass ,def query , def field ,def params = null) {
def q = new BasicDBObject()
def queryList = []
def allowedLanguages = ConfigurationHolder.config.grails.localizableString.allowedLanguages
allowedLanguages.each { locale ->
queryList.add(new BasicDBObject("values.${locale}", new BasicDBObject('$regex', /.*${query}.*/)))
}
q.put('$or',queryList)
def lsc = LocalizableString.collection.find(q)
def list = lsc.hasNext() ? domainClass.createCriteria().list(params) {
or {
while (lsc.hasNext()) {
def n = lsc.next()
eq("${field}",n._id)
}
}
} : null
return list
}
}
I'm not 100% on this, but I'm fairly certain the Mongo GORM plugin does not work with criteria relation traversal, which is what this looks like (despite not really being like that).
From mongoGorm website (http://blog.mongodb.org/post/18510469058/grails-in-the-land-of-mongodb):
Some of the GORM features that are not supported include:
Criteria queries on associations
HQL
Groovy SQL
So you may need to rethink the Map structure you have as a data model here :/ Anyone more experienced can weigh in?

Resources