Grails Criteria multiple hasMany intersection - grails

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")
}
}
}
}
}

Related

Search and get all parents that contains a child with value

class Client {
String name
static hasMany = [courses:Course]
}
class Course {
String name
static belongsTo = [client:Client]
}
I have this and I want to get all Clients that has a Course with name = "blabla"
I was trying to do : Clients.findWhere(Course.any { course -> course.name = "math" })
You can do this with criteria:
Client.withCriteria {
courses {
eq('name', 'math')
}
}
I believe that the following where query is equivalent to the above criteria:
Client.where { courses.name == 'math' }
or you may find you need another closure:
Client.where {
courses {
name == 'math'
}
}
but I rarely use where queries myself so I'm not 100% sure of that.
There are probably a lot of different syntactical expressions to achieve the same thing. I can say definitively that this works in my project though.
def ls = Client.list {
courses {
eq('name','math')
}
}

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.

GORM Criteria Query: Finding Children with specific properties

Have the following Domain modal:
class TransactionHeader {
static hasMany = [details: TransactionDetail]
}
class TransactionDetail {
static belongsTo = [header: TransactionHeader]
Product product
}
I'm trying to write a criteria query that will return all the TransactionHeader rows that contain TransactionDetails with 2 different Products. This is what I have so far and it isn't doing exactly what I'm after:
def list = TransactionHeader.withCriteria {
details {
and {
eq("product", product1)
eq("product", product2)
}
}
}
What's happening is it is return rows that contain at least 1 detail with 1 of the products. I need rows that have 2 details, each with one of the products.
Feels like you want to move details out of that, so actually
def list = TransactionHeader.withCriteria {
and {
details {
eq("product", product1)
}
details {
eq("product", product2)
}
}
}
Not sure how hibernate / gorm will deal this, though.
Have you tried using the "in" statement in your criteria dsl?
def list = TransactionHeader.withCriteria {
and {
details {
'in'("product", [product1, product2])
}
}
}

Using named queries

I have a named query in a domain class:
class Store {
static namedQueries {
openOnWeekends {
// some conditions here...
}
}
}
I know that I can do Store.openOnWeekends.list(), but I want to do something like this:
def pickupWeekendStores = Order.get(params.id).books.store.openOnWeekends
Is there a way to use named queries like that? Any suggestions on how to get the stores open on weekends?
Edit:
Order hasMany Book, Book hasMany Store
Named queries support additional criteria at invocation, so you could try:
Store.openOnWeekends {
books {
'in'('id', Order.get(params.id).books.collect { it.id })
}
}
Does doing something like:
Set<Store> pickupWeekendStores = Order.get(params.id).books*.store.collect { it.openOnWeekends.list() }
work?

createAlias() solution to return all associated rows does not work in all cases

Assuming the following domain objects:
UserChallenge {
String invitationKind
}
ChallengeGroup {
UserChallenge challenge
UserGroup group
}
UserGroup {
name
}
The following query returns challenges with a groups association which is partially filled with matching groups:
UserChallenge.withCriteria {
eq('invitationKind', 'GROUP')
groups {
'in'('group.id', visibleGroupIds)
}
}
In the post http://adhockery.blogspot.com/2009/06/querying-by-association-redux.html it suggests using createAlias() and modifying the query above seems to work:
UserChallenge.withCriteria {
eq('invitationKind', 'GROUP')
createAlias('groups', 'g')
'in'('g.group.id', visibleGroupIds)
}
However the following does not work:
UserChallenge.withCriteria {
or {
eq('invitationKind', 'OPEN')
and {
eq('invitationKind', 'GROUP')
createAlias('groups', 'g')
'in'('g.group.id', visibleGroupIds)
}
}
}
And returns only the challenges with matching visible group ids not the challenges which are 'OPEN'. It does not seem to matter where you put the createAlias() call.
The following does work:
UserChallenge.withCriteria {
or {
eq('invitationKind', 'OPEN')
and {
eq('invitationKind', 'GROUP')
groups {
'in'('group.id', visibleGroupIds)
}
}
}
}
except that it returns the challenges with only groups which match (the original problem I am trying to solve).
Although the question is old,anyone getting same problem might find it useful. Using detached criteria query is yet another idea for achieving it. According to the information provided in the question I have tried to accomplish it using detached criteria query. Please find more about detached criteria here
def userGroup = new DetachedCriteria(UserGroup).build {
eq("group.id", visibleGroupIds)
}
def getOb = UserChallenge.createCriteria()
def listReturned = getOb.list {
or{
eq('invitationKind', 'OPEN')
and {
eq('invitationKind', 'GROUP')
"groups" {
userGroup
}
}
}
}``

Resources