Use dynamic finders with list of Object IDs - grails

With the given class structure
class MyObject {
Status status;
}
class Status {
Integer id;
}
I want to use dynamic finders to query based on a list of Status ID values. What I want to be able to do is something like this
MyObject.findAllByStatusInList([1,2,3]);
This does not work though because my list needs to be Status objects. I know I can build a criteria to do this, but I just want to know if there is a way to accomplish this with Dynamic Finders?

You can still accomplish this using the dynamic finder.
def statuses = [1, 2, 3].collect { Status.load(it) }
MyObject.findAllByStatusInList(statuses)
load() will create a proxy for you that won't require retrieving the instance from the database as long as you don't access any properties other than id.

You can use the where clause:
MyObject.where {status.id in [1,2,3]}.find()
UPD
Dynamic finders don't support aliasing so Criteria (or DetachedCriteria) is the solution to be used.
In case if Status class is a domain entity you could retrieve a list of them (or load their proxies) from the database and then query MyObjects by the status list.
So I see no other appropriate solution but using Criteria in your case.

You can use this.
List<Integer > statuses = [1, 2, 3]
MyObject.findAllByStatusInList(statuses)

Related

Determine Data Type

I have this code in my controller:
def cols = grailsApplication.getDomainClass('com.archie.Build').persistentProperties.collect {it.name}
The code above will allow me to list all the property names I have in Build class. Now, I would like to include also the properties data type, ie. boolean, String etc...
Somewhat like the output is:
[floorType:String, floorWidth:Float, ......]
Maybe not exactly like that, or maybe similar, but as long as I can return their data type. Can someone help? Thank you.
Each entry in persistentProperties is a GrailsDomainClassProperty, and this provides access to the type of the property as a Class object:
def props = [:]
grailsApplication.getDomainClass('com.archie.Build'
).persistentProperties.each {
props[it.name] = it.type.name
}
Or just pass the persistentProperties array itself through to the GSP, then extract .name and .type there.
You may also wish to consider using constrainedProperties instead of/in addition to the persistentProperties. The constrainedProperties map lists only those properties that are mentioned in the domain class constraints block, but the iterator over this map is guaranteed to return the properties in the order they are listed in the constraints. This is how the default scaffolding operates, as I'm not aware of any way to control the order of the persistentProperties array.

GORM/Grails :: possible to query based on contents of a List within the model?

Assume the following:
class Thing {
String name
List<String> tags
static constraints = {
name(nullable: false)
tags(nullable: false)
}
}
I want to know if its possible, using GORM, to run a query for domain instances based on values in their respective lists
For instance: Are there dynamic GORM finders to query things like 'Find all Things that have the tag "Video" ', or 'Find all things with name = "Product1" that have the tag "Image" '
Just want to know if there's a nice concise way of doing this with Grails&Gorm, as opposed to retrieving a list of Things and iterating through it, finding the ones that have the appropriate tags and adding them to a results list.
Thanks!
One way (although not necessarily the most efficient!) would be to return the whole list of Things eg Thing.list() and then filter the resulting list using findAll.
List results = Thing.list().findAll{it.tags.contains("Image")}
How big is your list of Things and associated Tags likely to be?

Lazy fetching of objects using FindAllBy , for the first time

When I use criteria queries, the result contains array list of lazy initialized objects. that is, the list has values with handler org.codehaus.groovy.grails.orm.hibernate.proxy.GroovyAwareJavassistLazyInitializer.
This prevent me from doing any array operation (minus, remove etc) in it. When I use, GORM methods, I get array list of actual object types. How can I get the actual objects in criteria query?
The code is listed below.
availableTypes = Type.withCriteria() {
'in'("roleFrom", from)
'in'("roleTo", to)
}
availableTypes (an array list) has one value , but not actual object but value with a handler of GroovyAwareJavassistLazyInitializer
availableTypes (an array list) has values with type Type
availableTypes = Type.findByRoleFrom(from)
---------- Update ----------
I did further troubleshooting, and this is what I found. Probably the above description might be misleading, but I kept it in case it helps.
When using findAllBy for the first time, I get proxy objects rather than the actual instance. Then, I invoke the method through an ajax call, the actual instance is loaded (anything to do with cache loading??). When I refresh the page, it again loads the proxy
def typeFrom = Type.findAllByParty(partyFrom)
there is another use of findAllBy in the same method, which always returns actual instances.
def relFrom = Relation.findAllByParty(partyFrom)
When compared the two classes, the attribute 'party' of class Roles is part of a 1-m relation. like
class Role {
RoleType roleType
LocalDate validFrom
LocalDate validTo
static belongsTo = [party : Party ]
...
}
I know if I do statement like Party.findAll(), the role instances would be proxy till they access. But, when using gorm directly on the class (Role), why I am getting the proxy objects ???
thanks for the help.
thanks.
Turns out are a couple of possible solutions which I came across but didn't try, such as
Overloading the equals method so that the proxy and the domain
object use a primary key instead of the hashCode for equality
Using a join query so that you get actual instances back and not proxies
GrailsHibernateUtil.unwrapProxy(o)
HibernateProxyHelper.getClassWithoutInitializingProxy(object)
One solution that worked for me was to specify lazy loading to be false in the domain object mapping.
History of this problem seems to be discussed here: GRAILS-4614
See also: eager load

grails find first

I know this is simple question but taking more time
How to find first record from table in grails .
I need to get only the first record with out knowing the id number .
Is there any method like find :first in grails ?
thanks in advance .
Updating to Grails 2.1.1 or later adds two new methods (first and last) for GORM to address this needed feature.
From the docs:
class Person {
String firstName
String lastName
Integer age
}
// retrieve the first person ordered by the identifier
def p = Person.first()
// retrieve the first person ordered by the lastName property
p = Person.first(sort: 'lastName')
// retrieve the first person ordered by the lastName property
p = Person.first('lastName')
Well, you have to define by what measure this record is supposed to be the "first".
Assuming that you mean the record with the earliest creation timestamp, the easiest and most robust approach would be to add a dateCreated property to your domain class and then querying for the entity with the lowest such date. In fact you don't even have to set the creation date manually, because Grails does this for you (as long as you name the property dateCreated) - see Automatic timestamping in the Grails Documentation.
The HQL query would be something like:
def firstObject = YourClass.find("FROM YourClass ORDER BY dateCreated")
Check out hibernate criteria and projections, e.g:
def location = Location.createCriteria()
def firstRecord = location.list{
maxResults(1)
order("id","asc")//assuming auto increment just to make sure
}[0]
http://grails.org/doc/1.0.3/ref/Domain%20Classes/createCriteria.html
If timestamp doesn't matter, you could try if Daniel's answer without ORDER BY works, i.e.
def firstObject = YourClass.find("FROM YourClass")
You can use the grails findBy methods to return the first result of a query.
-> From the 1.3.7 docs
findBy*
Purpose
Dynamic method that uses the properties of the domain class to allow
the creation of Grails query method expressions that return the first
result of the query
-> from the latest docs
findBy* Purpose
Dynamic method that uses the properties of the domain class to execute
a query returning the first matching result.

How to order by more than one field in Grails?

Is there a way to get a list ordered by two fields, say last and first names?
I know .listOrderByLastAndFirst and .list(sort:'last, first') won't work.
Hates_ criteria answer didn't seem to work for me; putting "last,first" in order will only cause exceptions saying, "Property 'last,first' not found". To order on two fields, you can do the following:
def c = MyDomain.createCriteria()
def results = c.list {
and{
order('last','desc')
order('first','desc')
}
}
This is quite old but helped me in finding a suitable solution. A "cleaner" code example by using withCriteria shortcut:
def c = MyDomain.withCriteria {
and {
order('last', 'desc')
order('first', 'desc')
}
}
This old solution no longer works. Please see mattlary's answer below
You may have to write a custom finder in HQL or use the Criteria Builder.
MyDomain.find("from Domain as d order by last,first desc")
Or
def c = MyDomain.createCriteria()
def results = c.list {
order("last,first", "desc")
}
More complicated ordering criteria, (tested in Grails 2.1.0)
def c = MyDomain.withCriteria {
property {
order('last', 'desc')
}
order('first', 'desc')
}
sorts first by MyDomain.property.last then by MyDomain.first
MyDomain.findAll(sort: ['first': 'desc','last':'desc'])
works with grails-datastore-gorm:6.0.3
I think a criteria is the best bet, but you did the right thing by attempting a finder first. When retrieving domain objects from GORM, the right order to make the attempt is: dynamic finder, criteria, HQL.
This query is working on the basis of first field. When the first field is blank then it is shorted by the second field.
order('last','desc')
order('first','desc')
you can do this
def results=MyDomain.findAll([sort:"last",order:'desc'],[sort:"first",order:'desc']);
this line of code will first sort results from domain class "MyDomain" first by last name and then by first name of the person .
If you were sorting lists on the contents of their items, you would need to implement a comparator which would have some smarts to enable to you decide the sort order based on multiple properties.
Some examples of Groovy-style comparators are shown here
However if the list you are sorting is being returned from a database query, you would be better off sorting it using a CrteriaQuery and sorts on that
I has the same problem.
Since my list is not so big, I use groovy sort, as I want to sort on fields of linked domain:
CalendarData -> Attraction
def listCalendar (Calendar calendar) {
respond CalendarData.where {
calendar == calendar
}.list().sort{ "$it.attraction.type?:' '$it.attraction.name" }
}

Resources