Search and get all parents that contains a child with value - grails

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

Related

Gorm Criteria for "each in" / "none in"

I have to write some queries to implement a search in a complex data model. I want to use the Criteria DSL of Gorm to solve that.
For simple queries like the examples in the Gorm or Grails Documentation it's no problem, but I don't know, how to implement more complicated queries like
"each in", "none in" or "only one of x is in". I hope someone can give me a hint.
Grails Domain Classes:
class Content {
Integer contentNumber
static hasMany = [titles : Title]
}
class Title {
String title
Titletype titletype
}
class Titletype {
String name
}
Method with Criteria:
def filter(GrailsParameterMap args) {
//To ensure that the ids of titletypes to query are always given as Long[]
Long[] argsTitletype = [args.title.titletype.value].flatten() as Long[]
def query = new DetachedCriteria(Content).build {}
// Every Content, which has a Title with Titletype in argsTitletype
query = query.build {
titles {
'in'('titletype.id', argsTitletype)
}
}
return query.list()
}
The return of the query above has the expected result: All Content, which has a Titletype in argsTitletype
But how to query "Content, which has all the Titletypes in argsTitletype"?
I tried for example:
query = query.build {
titles {
and {
argsTitletype.each { tt ->
eq('titletype.id', tt)
}
}
}
or
query = query.build {
and {
argsTitletype.each { tt ->
titles {
eq('titletype.id', tt)
}
}
}
Where is my misstake? Have I to use Subqueries?
For your all-in Try the following out:
query = query.build {
titles {
titletype {
argsTitletype.each { tt ->
eq 'id', tt
}
}
}
}
you don't need ands here, as those are applied by default.

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 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?

Transient property in Grails domain

I have a Grails domain called People, and I want to check that each People has childs or not. Childs are other People objects. Here is my domain structure:
class People implements Serializable {
static constraints = {
name (nullable : false, unique : true)
createdBy (nullable : false)
creationDate (nullable : false)
}
static transients = ['hasChild']
static mapping = {
table 'PEOPLE'
id generator: 'sequence', params : [sequence : 'SEQ_PK_ID']
columns {
id column : 'APEOPLE_ID'
parentPeople column : 'PARENT_PEOPLE_ID'
}
parentPeople lazy : false
}
People parentPeople
String name
String description
Boolean hasChild() {
def childPeoples = People.createCriteria().count {
eq ('parentPeople', People)
}
return (childPeoples > 0)
}
}
But I cannot call people.hasChild() at anywhere. Could you please helpe me on this? Thank you so much!
It's because in eq ('parentPeople', People), Grails can't understand what "People" is (it's a class). You should replace "People" by this. For example:
static transients = ["children"]
def getChildren() {
def childPeoples = People.findAllByParentPeople(this, [sort:'id',order:'asc'])
}
Another way to get the same result is to use Named Queries. It seems more concise and was created specifically for this purpose. I also like it because it fits the pattern of static declarations in a domain model and it's essentially a criteria, which I use throughout my applications. Declaring a transient then writing a closure seems a bit of a work-around when you can declare named queries ... just my opinion.
Try something like this:
static namedQueries = {
getChildren {
projections {
count "parentPeople"
}
}
}

Resources