Grails: How to query objects in many to many mapping? - grails

Hello I have the follwing domain classes.
class Student {
int age
static hasMany = [courses:Course]
}
class Course {
String name
static hasMany = [students:Student]
}
I want to find the Students taking Course (with id 1), with age 7.
Could I do that with dynamic finder or criteria builder or HQL?
I do not want to do following as it load all students so inefficient:
def course = Course.get(1);
course.students.findAll{ it.age == 7 }

def studs = Student.withCriteria {
eq('age', 7)
courses {
eq('id', 1)
}
}
It's in GORM doc, section "Criteria/Querying Associations".

You can use a dynamic finder:
def students = Student.findByCourseAndAge(Course.load(1), 7)
By using load() instead of get() you avoid retrieving the whole Course instance and just reference its id.
Another option is HQL:
def students = Student.executeQuery(
'from Student s where s.course.id = :courseId and s.age = :age',
[courseId: 1, age: 7])

Related

How to save addTo in order by given date/id?

I need some help on my API, when I'm on web, the order is saving correct, but when its on API, it goes all wrong:
def test = parseJSON.sort { a, b -> a.ID <=> b.ID } //or dateTime, will print the same
//order when I print each of them
[IDWeb:0, conductivity:0, ReportId:2, dissolvedOxygen:0, levelWater:1, ID:1, ph:0, redoxPotential:0, temperature:0]
[IDWeb:0, conductivity:0, ReportId:2, dissolvedOxygen:0, levelWater:0, ID:2, ph:0, redoxPotential:0, temperature:0]
[IDWeb:0, conductivity:0, ReportId:2, dissolvedOxygen:0, levelWater:0, ID:3, ph:0, redoxPotential:0, temperature:0]
[IDWeb:0, conductivity:0, ReportId:2, dissolvedOxygen:0, levelWater:4, ID:4, ph:0, redoxPotential:0, temperature:0]
test.each{
def sample = new SampleWater()
sample.levelWater = it.levelWater
sample.conductivity = it.conductivity
sample.dissolvedOxygen = it.dissolvedOxygen
sample.redoxPotential = it.redoxPotential
sample.ph = it.ph
sample.temperature = it.temperature
water.addToSamples(sample)
}
return water
My problem is that addTo is not saving in order. How can I solve this?
Make sure you have defined the type of samples as a List in your Water domain class so that we can maintain the insertion order:
class Water {
static hasMany = [samples: Sample]
List<Sample> samples = []
}
class Sample {
def levelWater
}
By default implementation of hasMany is of type Set which does not maintain the insertion order but is responsible for uniqueness.
Since, now you samples will be saved in the same order as they are inserted.
You have to specify with order you want to apply to the list of SampleWater in the "water" domain class.
i.e:
class BlogCategory {
static hasMany = [
entries : BlogEntry
]
static mapping = {
entries: sort:'dateCreated', order:'desc'
}
}
In this example BlogEntry will be ordered respect dateCreated.

Criteria on domain which does not have reference of another domain

I have domain like
class Book {
Author author
String title
}
and another
class ListingTracking {
Book book
String oldVal
String newVal
Date modDate
static constraints = {
}
}
and now I need all those listingTacking which have a list of book ids but my criteria is on Book domain and I can not change association.
I tried
def books= Book.createCriteria().list {
'in'("id", [7,2,3,6].collect {it as Long} )
createAlias("listingTracking","lt")
projections{
property("title")
}
'in'("lt.book.id",[7,2,3,6].collect {it as Long})
}
I know that I can't create createAlias of listingTracking in Book domain but I need something like that, Is this possible via criteria?.
def listingTracking = ListingTracking.findAllByBookInList( Book.getAll([7,2,3,6]) )
Instead of Book.getAll you can use any finder you prefer on Books

How to limit the Relation Elements of a Class in Grails?

I have
class User {
String name
hasMany = [books: Book]
}
class Book (
String name
belongsTo = [user: User]
}
Now, I can access all books of a user instance as:
def user = User.find("someId")
println user.books
How can I limit the number of books such that I get only the first x books from user.books?
Is there also a way to sort them?
One viable approach is to define books as List inside User. You would need to have an index column but you could get the benefit of pagination and ordering like:
class User{
List books
static hasMany = [books: Book]
}
def user = User.find("someId")
println user.books?.getAt(3..10).sort{it.name}
Note:-
All books for User will be fetched lazily, using the above approach will filter books from index 3 till 10.
In case you want to optimize the lazy fetch strategy (N + 1), then you would probably need to have a look at batchSize and order. Also sort as a side note.
Example:
class User {
String name
static hasMany = [books: Book]
static mapping = {
books batchSize: 10
}
}
class Book (
String name
static belongsTo = [user: User]
static mapping = {
order "desc"
}
}

Grails 1:m get most relations

I'm relatively new to Grails.
I have the following
class House {
Integer number
Integer maxResidents
static belongsTo = [town: Town]
}
class Town {
String name
static hasMany = [houses: House]
}
I want to get five towns with most Houses. I have seen the possibility to create a criteria but I can't deal with it now. Can someone support?
Thank you!
As you have a bidirectional association you can do this with a query on House:
def result = House.withCriteria {
projections {
groupProperty("town", "town")
rowCount("numHouses")
}
order("numHouses", "desc")
maxResults(5)
}
This would return you a list of results where each result res has the town as res[0] and the number of houses as res[1]. If you'd prefer each result to be a map giving access to res.town and res.numHouses then you should add
resultTransformer(AliasToEntityMapResultTransformer.INSTANCE)
after the maxResults line (along with the appropriate import at the top of your file).

Grails GORM Domain class relationship

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 {}
}
}

Resources