I've got a domain class which I want to, at run time, do a database call to populate a list of objects as a property. I have a tree with a 'headMember' property and that property is an object which has the following function:
def marriages = {
def marriages = Marriage.findAll("from Marriage as m where m.mainMember.name=:name", [name:name])
return [marriages:marriages]
}
in my GSP, I use ${tree?.headMember?.marriages} to access the 'headMember' property of the model which is passed to the view 'tree' from the following function in the relevant controller:
def show = {
def tree = Tree.get(params.id)
render(view:'show', model:[tree:tree])
}
when I view this in my browser, i get:
Member$_closure1#3708ab98
where I'd expect a list.
Any ideas what I'm doing wrong?
Cheers.
When you call marriages, you are calling a closure and this closure is returned. I think that you should rework it to be a method, something like that:
static transients = ['marriages'] // tell hibernate that marriages is not a persistent property
List<Marriages> getMarriages(){
return Marriage.findAll("from Marriage as m where m.mainMember.name=:name", [name:name])
}
This way, when you call ${tree?.headMember?.marriages} in your GSP, the getMarriages() method is called and list of marriages should be returned.
Related
How can I pass variable holding a value instead of passing a value directly to groovy search criteria?
for (def payee in payees)
{
def results = resp.cases.find("eq 'hrid','7547') // hard code values work
def results = resp.cases.find("eq 'hrid',??????) // how can I pass payee
}
I'm new to this. Please help. thanks
Basing on examples, check it:
def results = resp.cases.find { case -> case.hrid == payee }
GORM criteria queries are quite different than your example. Let's say you have a Payee domain class with a property named hrid:
grails-app/domain/com/something/Payee.groovy
class Payee {
String hrid
}
To get a list of all the Payee instances with an hrid of 7547, you'd run a criteria query like this:
String hridValue = '7547'
List payees = Payee.withCriteria {
eq 'hrid', hridValue
}
I explain Grails GORM queries in depth in a series of articles starting right here.
I have an object where I need to query and return it as a Map, but I don't want to iterate over the object again as I'm already doing a query and it can get a bad performance.
List<MyObject> myObjectList = MyObject.createCriteria().list(params) {
...
}
But what I need is a Map like:
myObjectList.each { MyObjectList myObject ->
myMap.add([person: myObject.person, myObject: myObject, listIntoObject: myObject.listInsideObject as List])
}
I found another way to get a map like this but it still not the better way to get a Map from a List that I'm querying with GORM...
myMap = myObjectList.collect{ [person: it.person, myObject: it, listIntoObject : it.invoiceDetails as List] }
Is there a better way to get a Map using GORM?
You can use org.hibernate.transform.Transformers to transform the result to an entity map
import org.hibernate.transform.Transformers
def criteria = MyObject.createCriteria()
criteria.resultTransformer(Transformers.ALIAS_TO_ENTITY_MAP)
def myObjectList = criteria.list(params) {
...
}
You can also fall back to HQL as well. Refer the UPDATE section of a similar answer for more details.
You can use import org.hibernate.criterion.CriteriaSpecification with withCriteria() to transform the result in a Collection object, with properties chosen by you only:
import org.hibernate.criterion.CriteriaSpecification
def criteria = User.withCriteria(){
resultTransformer CriteriaSpecification.ALIAS_TO_ENTITY_MAP
createAlias 'personalData', 'p'
eq 'id', params.id
// ...and so on, then
projections {
property 'id', 'myId' // a property called 'myId', from User
property 'p.name', 'userName' // from personalData, a property mapped by a fk in User
property 'p.age', 'age'
}
}
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'))
When using projection on the properties, the result is returned as the list with the elements in the same sequence as that defined in the projections block. At the same time the property names are missing from the list and that is really disadvantageous to the developer as the result would be passed along and the caller needs to know what value belongs to which property. Is there a way to return a map from the Criteria query with property name as the key to the value?
so, the following code:
def c = Trade.createCriteria()
def remicTrades = c.list {
projections {
property('title', 'title')
property('author.name', 'author')
}
def now = new Date()
between('publishedDate', now-365, now)
}
This returns:
[['book1', 'author1']['book2', 'author2']]
Instead I would like it to return:
[[book:'book1', author:'author1'][book:'book2', author:'author2']]
I know I can arrange this way after getting the result but I earnestly feel that the property alias should have been used by the criteria to return a list of map that mimics the result of the SQL query and not a bland list.
Duplicate: Grails queries with criteria: how to get back a map with column?
And the corresponding answer (and solution): https://stackoverflow.com/a/16409512/1263227
Use resultTransformer.
import org.hibernate.criterion.CriteriaSpecification
Trade.withCriteria {
resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
projections {
property('title', 'title')
property('author.name', 'author')
}
def now = new Date()
between('publishedDate', now-365, now)
}
Agree with your question reasoning, this really should be part of the core GORM solution. That said, here's my workaround;
def props = ['name','phone']
def query = Person.where {}.projections {
props.each{
property(it)
}
}
def people = query.list().collect{ row->
def cols = [:]
row.eachWithIndex{colVal, ind->
cols[props[ind]] = colVal
}
cols
}
println people // shows [['name':'John','phone':'5551212'],['name':'Magdalena','phone':'5552423']]
I am trying to use recursion in groovy to traverse a tree relationship. The below code runs one cycle, upto childNodes && recurClosure(childNodes ) , but doesn't call the closure recurClosure again. At that instant childNodes had two objects (array list) same type as root.
In the code, recurClosure is defined and calls with a list of objects (root). It then iterates through each element and fines the child nodes (uses grails dsl for this).If the childNodes is not null, it recursively calls the parent method.
Should I break it up, or what is wrong?
def parentval
def root = Domain.list()
def recurClosure
recurClosure = {inroot ->
inroot.each {
returnList << it
parentval = it
childNodes = Domain.withCriteria {
eq('parent', parentval )
}
}
childNodes && recurClosure(childNodes )
}(root)
return returnList
}
thanks in advance.
Update: The following exception is noted
ERROR [2010-06-24 08:20:04,742] [groovy.grails.web.errors.GrailsExceptionResolver] Cannot invoke method call() on null object
java.lang.NullPointerException: Cannot invoke method call() on null object
at com.bsr.test.DomainService$_closure2_closure7.doCall(com.bsr.test.DomainService:68)
at com.bsr.test.DomainService$_closure2.doCall(com.bsr.test.DomainService:58)
at com.bsr.test.DomainController$_closure3.doCall(DomainController.groovy:45)
at com.bsr.test.DomainController$_closure3.doCall(DomainController.groovy)
at org.apache.shiro.web.servlet.ShiroFilter.executeChain(ShiroFilter.java:687)
at org.apache.shiro.web.servlet.ShiroFilter.doFilterInternal(ShiroFilter.java:616)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:81)
at java.lang.Thread.run(Thread.java:619)
Update 2: Now trying Daniel's suggestion.
{ inroot ->
inroot.each {
returnList << it
parentval = it
childNodes = Domain.withCriteria {
eq('parent', parentval )
}
if(childNodes)
call(childNodes)
}
/*if(childNodes)
call(childNodes)*/
}(root)
In the above implementation, root is an arraylist, The inner closure takes each element out of it and recursively calls the anonymous closure. When I moved the 'call' inside the each closure, it doesn't call the outer anonymous closure, but the inroot.each {} itself. So, I get an error
ERROR [2010-06-24 08:47:46,438] [groovy.grails.web.errors.GrailsExceptionResolver] instance not of expected entity type: java.util.ArrayList is not a: com.bsr.test.Domain
I see a blog post about how to name the closure through 'this' > I'll update my finding.. thanks
Update 3: The way to call the outer closure is owner.call(childNodes)
The problem is, that by
recurClosure = {
[...]
}(root)
you don't assign the closure to recurClosure, but rather the return value of its invocation! Thus, of course, you can't call the closure via recurClosure()...
Two possible solutions:
First define the closure, and then call it separately, as air_blob suggested:
def recurClosure = {
[...]
}
recurClosure(root)
Use the implicit call() function for recursion. This way you can even work with an anonymous closure. IMHO a very nice way to implement recursion in Groovy:
{ inroot ->
inroot.each {
returnList << it
parentval = it
childNodes = Domain.withCriteria {
eq('parent', parentval )
}
}
if(childNodes)
call(childNodes)
}(root)
Two more comments on your code:
You may want to declare returnList: def returnList = []
While childNodes && recurClosure(childNodes ) may do what you want, it's much more readable to sacrifice one more char and spell out the if.. ;-)
Don't you want to recursively call your closure inside the each?
Another (higher-level) remark on your code: If the parents and their children are of the same type (Domain), won't Domain.list() actually return all children, too? Is there really a need for traversing the tree manually?
Do you get any exceptions?
Have you tried invoking it separately like this:
def recurClosure
recurClosure = {inroot ->
[... stuff ...]
}
recurClosure(root)
What exactly do you want to do in this line:
childNodes && recurClosure(childNodes )