I am facing a problem with projections in createCriteria - grails

I am facing a problem to get the required result from this closure
def authors{
results = Message.createCriteria().list {
projections {
author{
groupProperty('id', 'authorId') // 2nd param is alias
property('username', 'username')
}
}
and{
...
...
}
}
[authors:results]
}
I want to show this list on my gsp page
and wants to access the values using aliases
(while above criteria is returning a list of arrays)

Use resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP).
import org.hibernate.criterion.CriteriaSpecification
Message.createCriteria().list {
resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
projections {
author{
groupProperty('id', 'authorId')
property('username', 'username')
}
}
}
All projections must have aliases. Otherwise the resulting map will contain nulls.

You can try this
def authors{
results = Message.createCriteria().list {
projections {
author{
groupProperty('id')
property('username')
}
}
and{
...
...
}
}
List authors = results.collect{record -> [authorId : record[0], username:record[1]}
[authors:authors] }

Related

Using Disjunction (logical or) in Grails Subqueries

In Grails 2.5.4, I am having issues using a disjunction in Subqueries. If I have a query like the following:
DomainObj.createCriteria().list {
def criteria = new DetachedCriteria(DomainObj2).build {
or {
eq('prop1', someVal)
eq('prop2', someVal)
eq('prop3', someVal)
}
projections {
distinct('id')
}
}
inList('prop', criteria)
}
The 'or' part of the query fails with a null pointer exception. The reason seems to be in AbstractHibernateCriterionAdapter the code is looking for a PersistentEntity for the DetachedCriteria which is never assigned.
The only workaround I have found is to switch the query to use more subqueries like this:
def criteria1 = new DetachedCriteria(DomainObj2).build {
eq('prop1', someVal)
projections {
distinct('id')
}
}
def criteria2 = new DetachedCriteria(DomainObj2).build {
eq('prop2', someVal)
projections {
distinct('id')
}
}
def criteria3 = new DetachedCriteria(DomainObj2).build {
eq('prop3', someVal)
projections {
distinct('id')
}
}
DomainObj.createCriteria().list {
or {
inList('prop', criteria1)
inList('prop', criteria2)
inList('prop', criteria3)
}
}
Which sidesteps the issue, and really isn't ideal. Any idea what is going wrong?
Update
So after looking around some more I found this issue on Github. What I am experiencing is a bug that was fixed in grails-data-mapping version 5.0.2. So for anyone that searches for this issue in the future it looks like the you either have to upgrade or use the crazy workaround highlighted above.
You could probably simplify your above working nest to:
private DetachedCriteria getCriteria(prop,val) {
return new DetachedCriteria(DomainObj2).build {
eq(prop,val)
projections {
distinct('id')
}
}
DomainObj.createCriteria().list {
or {
inList('prop', getCriteria('prop1','somVal'))
inList('prop', getCriteria('prop2','somVal'))
inList('prop', getCriteria('prop3','somVal'))
}
}
Personally I would probably either just do a findAll or just run an hql query, if it turns out you can't use the current method due to some limitation since am no expert on this matter itself.
//where d.domainObject2 is the binding of DomainObj2 within DomainObj
String query="select new map(d.id) from DomainObj d left join d.domainObject2 d2 where d2.field in (:someList)"
def input=[]
input.someList=[1,2,3] //The or segments
def results=DomainObj.executeQuery(query,[],[readOnly:true,timeout:15,max:-1])

CreateCriteria - Use logical OR in hasMany association

I want to get instances who contain in their lists (firstsList or SecondsList) a specific user.
In my solution, the create criteria takes into account only the first list of users.
It seems to be a bad usage of the logical OR
Domain
class ClassA {
static hasMany = [firstsList:User,SecondsList:User]
}
Service
def idList = ClassA.createCriteria().list () {
projections { distinct ( "id" )
property("name")
property("id")
}
or {
firstsList{eq("login", 'John')}
SecondsList{eq("login", 'John')}
}
order("name","desc")
}
return idList
The reason behind this is hibernate by default uses inner join. But in your case you need left join. For that you can use createAlias of createCriteria.
def idList = ClassA.createCriteria().list() {
projections {
distinct("id")
property("name")
}
createAlias("firstsList", "fl", JoinType.LEFT_OUTER_JOIN)
createAlias("SecondsList", "sl", JoinType.LEFT_OUTER_JOIN)
or {
eq("fl.login", "John")
eq("sl.login", "John")
}
order("name", "desc")
}

Grails Criteria multiple hasMany intersection

I've been trying to query with multiple hasMany objects, such as:
def product = Product.createCriteria().list {
createAlias("productAttributeValues", "pav")
and {
if (session.filters?.filter_instore) {
and {
eq("pav.attribute", Attribute.findByCode("instore"))
eq("pav.valueDe", session.filters?.filter_instore?.toString())
}
}
if (session.filters?.filter_promo) {
and {
eq("pav.attribute", Attribute.findByCode("promo"))
eq("pav.valueDe", "1")
}
}
}
}
This doesn't seem to work, since I never get a result set, although I have test data that would match. It seems that the problem is that I'm querying twice with the same objects.
One possible solution would be to query the productAttributeValues seperately and then intersect with a "in"("myPavs", pavs) - but this seems to be inefficient to me.
Any thoughts?
Thanks.
I would re-build your query so:
def products = Product.withCriteria{
productAttributeValues{
or{
if (session.filters?.filter_instore) {
and {
eq("attribute", Attribute.findByCode("instore"))
eq("valueDe", session.filters?.filter_instore?.toString())
}
}
if (session.filters?.filter_promo) {
and {
eq("attribute", Attribute.findByCode("promo"))
eq("valueDe", "1")
}
}
}
}
}

gorm withCriteria and groping by domain class property

I have the following entities in my app :
class Statistic {
int hour
...
Widget widget
}
class Widget {
String name
...
}
And I also have StatisticObj that is just DTO of Statistics domain
class StatisticObj {
int hour
...
String widgetName
}
I want to make criteria which would count Statistic and group by widgetName (so in the end I have count of Statistic per each widngetName) and then convert result to list of StatisticObj. My Criteria looks like this:
def results = Statistic.withCriteria {
groupProperty('widget.name', 'widgetName')
..... projections { count ...}
}
resultTransformer(Transformers.aliasToBean(StatisticObj.class))
}
but in the end I get result which is not grouped.
What I'm doing wrong? Thanks
For first groupProperty must be in projections. And it take only one property.
projections{
groupProperty('widget.name')
count
}
Try it I think it must resolve problem
.withCriteria {
createAlias('widget', 'w')
...
projections {
groupProperty("w.name", "displayValue")
}
....
}
works now!

Grails controller search criteria with list

I need to do a search based on various criteria.
if a name contains the specified string.
if the name contains the specified string and a string from a list.
if the name contains one of the strings from a list.
I have the following code but it doesn't work. How bad is this code?
def taskList = Object.createCriteria().list(params) {
if (params.query) {
ilike("name", "%${params.query}%")
}
if (params.nameList) {
params.nameList.split("&").each {
or {
ilike("name", "%${it}$%")
}
}
}
The result is empty for use cases 2 & 3. What am I doing wrong? How should I do it?
Cheers
I'd use in operator for 3. case
list{
or{
if( params.query ) ilike "name", "%${params.query}%"
if( params.nameList ) 'in' 'name', params.nameList.split("&")
}
}
def taskList = Object.createCriteria().list(params) {
def names = []
if(params.nameList){
names = nameList.split("&")
}
or{
if (params.query){ilike("name", "%${params.query}%")}
and{
if (params.query){ilike("name", "%${params.query}%")}
if(names){'in'('name', names)}
}
if (names) {
names.each {name->
or {
ilike("name", "%$name$%")
}
}
}
}
}
Untested, but can you try with above. I would rather go with an HQL to achieve what you needed.

Resources