I have an class with an hasMany on a Long:
class Test {
static hasMany = [longList:Long]
}
I want to filter on longList with Criteria:
Test.createCriteria().list{
'in'('longList',[Long.valueOf('1')])
}
I get an SQLException: No value specified for parameter 1.
The SQL looks like this:
select * from test this_ where this_.id in (?)
i tried things like:
createAlias('labours', 'l')
eq('l',Long.valueOf(filter.labourId)) )
or
eq('labours.value', Long.valueOf(filter.labourId))
But i can't get it working.
For a workaround i would make another domain Class:
class Test {
statis hasMany=[longList:TestLongList]
}
class TestLongList{
Long longListItem
static belongsto = [test:Test]
}
This should be working but i must always create an TestLongList Instance if I create an Test Object, so the code would turn from:
test.addToLongList(Long.valueOf('22'))
to
TestLongList tll = new TestLongList
tll.test= test
tll.longListitem = Long.valueOf('22')
tll.save()
test.addToLongList(tll)
Is there a way to stay with the Long-List without HQL?
You have to rewrite the criteria to look like this:
Test.createCriteria().list{
createAlias('longList', 'l')
'in' ('l.elements', [1L])
}
This boils down to the property name under which Hibernate stores collection (elements).
Related
I have a domain class
class Url {
UUID id
String url
static hasMany = [
indications:UrlIndication
]
...
}
And
class UrlIndication {
UUID id
String name
static belongsTo = Url
...
}
I want to choose urls so that it has all the necessary UrlIndication elements in a given list indicationsId.
For that I use an association and criteria like this one:
indications {
and {
indicationsId.each{
indication->
eq ('id',UUID.fromString(indication as String))
}
}
}
However, all I got is an empty result. Can you suggest any modifications/ other methods so that I can do this? Thanks in advance
Your query returned an empty list because it's the equivalent of the expression (pseudo-code): if 1 = 1 and 1 = 2 and 1 = 3
Such an expression would always be false. in or inList would not work for the reason #innovatism described.
In theory, Criteria's eqAll() or HQL's = ALL would work. But, I don't know for sure because I could not get either one to work.
What will work is to use inList to return a subset of Urls: those which contain at least one of the UrlIndication IDs. Then use Groovy's containsAll() to finish the job.
def ids = indicationsId.collect { UUID.fromString(it as String) }
Url.createCriteria()
.buildCriteria {
indications {
inList 'id', ids
}
}
.setResultTransformer(org.hibernate.Criteria.DISTINCT_ROOT_ENTITY)
.list()
.findAll {
it.indications.id.containsAll(ids)
}
Since the query has the potential to return duplicate Url instances, the ResultTransformer is set to return a unique list.
Finally, findAll() is used along with containsAll() to filter the list further.
Using eqAll (maybe)
Something like the following might work. Something funky is going on with Grails' HibernateCriteriaBuilder that causes the eqAll method to look up properties in the root entity; completely ignoring the sub criteria. So the following uses Hibernate directly. It didn't work for me, but it's as close as I could get. And it gave me a head-ache!
Url.createCriteria().buildCriteria {}
.createCriteria('indications', 'i')
.add(org.hibernate.criterion.Property.forName('i.id').eqAll(org.hibernate.criterion.DetachedCriteria.forClass(UrlIndication)
.add(org.hibernate.criterion.Restrictions.in('id', ids))
.setProjection(org.hibernate.criterion.Property.forName('id'))
))
.setResultTransformer(org.hibernate.Criteria.DISTINCT_ROOT_ENTITY)
.list()
The problem I had is I could not get Restrictions.in to work. Restrictions.eq works fine.
the in clause should do:
indications {
'in' 'id', indicationsId.collect{ UUID.fromString indication.toString() }
}
I have two domain class
class Company{
String name
....
static hasMany[product:product]
}
class Product{
String Pname
String Qty
}
i am tring to add product like this
Company comp= Company.get(1)
Product pdct = Product.findByPname("procut1");///procunt name is unique
comp.product.add(pdct)
comp.save(flush:true)
the above statement are successfully executed
but when i try to find comp.product i got a empty list like []
i also try addTo but this give exception
so what m i missing?
You should be using the GORM methods for addTo and removeFrom when adding and removing members of your collection.
comp.product.add(pdct)
should be:
comp.addToProduct(pdct)
Change this as static hasMany[products:Product]
Company comp= Company.get(1)
Product pdct = Product.findByPname("procut1");///procunt name is unique
comp.addToProducts(pdct)
comp.save(flush:true)
Also add static belongsTo = [company:Company] in your Product class to apply Cascade operations
I ran into some problems while trying to count items.
Imagine the following domain classes
class Book {
String name
}
class Author {
String name
static hasMany = [books:Book]
}
How do I get a list of Authors sorted by number of Books?
here's my try:
def c = Author.createCriteris()
c.list {
projections {
count 'books', 'numBooks'
groupProperty 'id'
}
order 'numBooks', 'desc'
}
but somehow I get only unusable results... and I don't know how to join the Author objects to the rsult list.... :-(
Havent tried it, but couldn't you do something like:
class Author {
String name
static hasMany = [books:Book]
static namedQueries = {
sortByMostBooks {
books {
order('size', 'desc')
}
}
}
}
And then get access by the cleaner named query
Author.sortByMostBooks.list();
In addition, you may want to include a belongsTo in you Book domain class:
static belongsTo = Author;
or:
static belongsTo = [authors:Author];
if a book is likely to have multiple authors
got something!
I still don't know how to do it with a criteria, but by switching to HQL, I succeeded.
So if someone comes up with a criteria solution, he will still get the bonus for the correct answer :-)
here is my query:
Author.executeQuery("""
select
a, size(a.books) as numBooks
from
Author a
group by
id
order by
numBooks DESC
""",[max:20])
This query isn't efficient, since it fetches all Authors in a loop, but that's ok for now.
i have domain classes:
package test
class Credit {
String name;
static hasMany = [debts : Debt]
static constraints = {
}
}
and
package test
class Debt {
Integer amount;
Date date;
static belongsTo =[credits: Credit]
static constraints = {
}
}
Need: select max: 10; order: "desc"; sort: "date" rows of Debt associated with the Сredit.get(id)
How can i do it?
solution:
Debt.findAllByCredits(Credit.get(params.id),[max:10, sort:"date",order:"desc"])
but next question about this example:
why, this code work:
def ok = Debt.findAllByCredits(Credit.get(params.id),[max:10, sort:"date",order:"desc"])
println "true:" + ok
but this code not work correct:
def dd = new Debt(credits: Credit.get(params.id))
def wrong =Debt.findAll(dd)
println "no: "+ wrong
all time return all records in table, why?
you could do something like
def hql = "select d from Debt d where credits = ? order by d.date desc"
Debt.findAll(hql, [credit], [max:10])
you might have to tweak that, but something similar should work. Also note, I am assuming that you have an instance of credit that is the parent of the Debts.
You can also use the methods Grails generates dynamically at runtime, based on the properties of your classes
Debt.findAllByCredit(credit, [max:10,sort:"date",order:"desc"]
again, you will need a reference to a credit object.
Check out the docs at
http://grails.org/doc/latest/
specifically the section on findAll and findAllBy under Domain Classes in the left hand nav.
Grails 1.1.1
Goovy 1.5.7
In a relationship such this:
Author 1 -- n Book n -- 1 Publisher
Defined in Grails:
class Author {
String firstName
String lastName
static hasMany = [books: Book]
static constraints = {
books(nullable: true)
}
}
class Book {
String title
Author author
Publisher publisher
static constraints = {
author(nullable: true)
publisher(nullable: true)
}
}
class Publisher {
String name
static hasMany = [books: Book]
static constraints = {
books(nullable: true)
}
}
I want to load a Book with the values of Publisher and Author.
When i get a Book with the query:
def book2 = Book.findAllByAuthor(author)
I get the response with the autor assosiated but the publisher only have the id and name class in the other query:
def book3 = Book.findAllByPublisher(publisher)
I retrieve me the inverse result,i have the book with the publisher data but the author only have the id and the class name.
Where is the error in the defined model ? o there is an error in the way to do the queries ?
Edit:
I need the way to retrieve the values only with the query like this:
def book2 = Book.findAllByAuthor(author, [fetch:[publisher:'eager']])
In this one I can manage the value of publisher.
Question: If publisher had a hasmany or Domain related, getting the book I'm able to read the attributes?
Thanks.
Thanks.
Lazy fetching is used by default with gorm associations. If you want to enable eager fetching, you can modify the ORM DSL by adding the following mappings block to your Author domain class:
static mapping = {
books lazy:false
}
or you could change the fetch mode in the domain object by adding following code after your books relationship is defined.
static fetchMode = [books:"eager"]
Doing the same to your Publisher domain object should allow you to accomplish what you want. You do want to be careful of the consequence that you may load more data than you intend to.
Shouldn't the get() method return what you are looking for?
Example: def book2 = Book.get(author)
You'd better use Criteria and explicitly define which relations should be loaded eagerly. Just mention relation in the query.
Example:
def c = Teacher.createCriteria()
List<Teacher> results = c.list {
subjects {
attendees {}
}
}