I have been trying for this. But don't know it is possible or not. I need to list records by writing a crieria query on super class with conditions on subclass.
Say, Cats, Dogs extends Animal class. I need to list all animals but dogs with black dots and cats with white color. Here the key problem is, dog's properties are not in cat domain class.
But i have to write createCriteria on Animal class so that i can paginate with all animals or am i missing something?.
given that you use tablePerHierarchy = true you should be able to write a native SQL query to select the records from the table by where-clauses pointing to partially null-ed columns:
Anumal.withCriteria{
or{
sqlRestriction "dots is not null and dots != 'black'" // dogs
sqlRestriction "color = 'white'" // cats
}
}
Related
I'm working on some sort of advanced search feature with variable fields. Some of the search fields are lists of some primitive(ish) objects (String, enums, etc.). I want to be able to retrieve records whose values are a subset of some given list.
To illustrate, say I have a Book class (assume the model is appropriate this way):
class Book {
...
List authors = []
...
}
In addition say we have the following book records:
Book(title: 'Great Expectations of Tom Sawyer', authors: ['cdickens', 'mtwain'])
Book(title: 'Huckleberry Potter in Bleak House', authors: ['cdickens', 'mtwain', 'jrowling'])
Book(title: 'A Christmas Carol', authors: ['cdickens'])
Then, I'm given a list of author (names) authorFilter = ['cdickens', 'mtwain'] to search for any collaborative works of cdickens and mtwain. How do I express this using GORM's where construct? Is it even possible to cover this using it?
Basically, what I want to do is:
Book.where {
authorFilter.every { it in authors }
}
This question has come up before. Unfortunately, where nor criteria queries have an every() equivalent. But there's a hack that may work for you. But first, I'll expand on your domain model.
Domain model
class Book {
String title
static hasMany = [authors: Author]
static belongsTo = Author
}
class Author {
String name
static hasMany = [books: Book]
}
HQL query
Using the domain model described above, you can use the following HQL query.
def hql = """
SELECT b FROM Book AS b
INNER JOIN b.authors AS a
WHERE a.name in :authors
GROUP BY b
HAVING COUNT(b) = :count
"""
def books = Book.executeQuery(hql, [authors: authorFilter, count: authorFilter.size()])
How it works.
You can read about how this query works in the other question I mentioned.
I don't think this is any better than #EmmanuelRosa's answer but I have another approach using HQL and the executeQuery method.
Using the same domain model he's given in his answer, I use the MEMBER OF expression to restrict the results.
def authorFilter = [Author.get(1)]
def authorMemberOfRestriction = ""
def namedParameters = [:]
authorFilter.eachWithIndex{ aut, ind ->
authorMemberOfRestriction += ":author${ind} MEMBER OF b.authors AND "
namedParameters.put("author" + ind, aut)
}
namedParameters.put('count', authorFilter.size())
def hql = """
FROM Book b
WHERE
(
${authorMemberOfRestriction}
size(b.authors) = :count
)
"""
def books = Book.executeQuery(hql, namedParameters)
Mine is somewhat different in that the authorFilter is a collection of Author domain class instances; I found it to work much easier for the MEMBER OF expression and truthfully is more of a depiction of how the real data would be modeled.
You can see that I build the multiple MEMBER OF expressions with the eachWithIndex, using the index on both sides of the named parameters. It's not exactly pretty but I don't believe there is a way around this and still use this approach.
I think #EmmanuelRosa's approach is probably the 'cleaner' option but the MEMBER OF approach makes more sense in my head as far as the logic is concerned.
There doesn't seem to be a simpler way of doing this other than doing HQL query. Taking hints from this answer to a very similar question, I figured out a solution to my problem.
To be clear, the Book should already have relation to many String using the hasMany construct:
class Book {
...
static hasMany = [authors: String]
...
}
To fetch results:
def results = Product.executeQuery("select p from Products p join p.tags t where t in :tags", [tags: givenTags])
I have a POGO we'll call Foo and it has a list of Bars. In the database, these are simple integers, but they're stored in a separate table (Foo_Bars)
class Foo {
String name
...
static hasMany = [bars:Integer]
...
}
So my question is, how do I create a query to find all Foos that with bars that are in a list. I know how I would write it in SQL.
SELECT * FROM foo, foo_bars
WHERE foo.id = foo_bars.foo_id
AND foo_bars.bars_integer IN (11, 15, 52)
But I figure there must be a simpler way, using GORM or HQL. How would I write this?
but what exactly you want to achieve? list of Foo's where bars is equal to (11,15,52), or ONE OF bars is in the list or the list of bars contain each of given list?
either way, I doubt you can do it in criteria or using a dynamic finder, I'm trying to do it in an unit test and nothing worked
I would go with creating another domain class like
class FooBar {
Foo foo
Integer integer
}
which would create exactly the same database table as you already have, and then querying would be much simpler
I am trying to just return a single string from each object.
Given the following:
class Book {
String title
Date releaseDate
String author
Boolean paperback
}
for every instance of Book I want to get an array of authors then make them unique.
I thought you could do something like:
def authors = Book.findAllByAuthor()
This just gives me an array off book objects.
I know i can do a
a =[]
authors.each{a.add(it.author)}
a.unique()
I am almost certain there is a way just to grab all authors in one line.
any ideas?
This gives you distinct authors of any book:
Book.executeQuery("select distinct author from Book")
You can use projections to get a distinct list of authors across all books. Take a look at the createCriteria documentation for more examples.
def c = Book.createCriteria()
def authors = c.list() {
projections {
distinct('author')
}
}
I Have the following two classes:
class Person{
String name
static hasMany = [
items: Item
]
}
class Item{
String name
}
Multiple Persons can also have the same Item. I'm trying to get a list of all Persons that have a specific item in their collection. I.E. Both Person A and B have Item A in their list so return them both. Unfortunately their is no findAllByCollectionContains() the closest is is findAllByCollection() which requires an exact set.
I've been trying executeQuery to give me a but more control and haven't come up with anything yet.
Example of what I have tried:
Person.executeQuery("select name from Person p where ? in p.items",[item])
Any suggestions?
You have to join the items collection, then you can query on it easily
Person.executeQuery("select name from Person p join p.items as i where i = ?",[item])
I have the following scenario,
Domain class A which hasMany B's
Domain class B which hasMany C's and belongsTo A
Domain class C which belongsTo B
Class E {
A a
B b
C c
}
Class C {
String name
}
I want to query E values i.e get a list of some E property eg in this case c.name based on values selected by a user in a select box, i.e user selects A and B from multiple select boxes and based on this criteria, a list of names is obtained.
in other words i want to find all names in c which satisfy condition set by a and b
have tried to figure out the GORM query to no avail.
thanks
I solved this by using raw SQL joins. Not really certain if this was the best way but it worked for me.
I got the parameters from A and B, ie
def fromA = params.someCriteriaValueInA
def fromB = params.someCriteriaValueInB
Please note that these are fetched from a gsp. Also, fromB values would be loaded based on fromA values, using chained selects.
In the grails controller/service ...
def db = new Sql(dataSource)
def result = db.rows("your sql to go here")
Then you can do whatever you want with the results, for example manipulate it in a template
render(template: "myResults", model:[result :result])
Dont forget to inject the dataSource bean in your controller/service, and also doing the necessary import
import groovy.sql.Sql
Please note that this involved traversing many domain class instances, and for those who like raw SQL this would seem easier.Would appreciate a different approach, maybe using GORM's criteria.