Grails Many-To-Many - Problems of dynamic finder - grails

I hope you can help me guys. Google unfortunately didn't helps me out and my search here at stackoverflow didn't as well :-(
I have two DomainClasses HumanResource and Task with a many-to-many relationship.
Model-Definitions:
Task:
class Tasks {
String name
static belongsTo = [HumanResource]
static hasMany = [humanResources: HumanResource]
//also tried but didn't help -> static fetchMode = [humanResources:"eager"]
}
HumanResource:
class HumanResource {
String name
static hasMany = [tasks: Tasks]
}
I also tried to add an index on the id-field with mapping={} but I also think that's not the solution, it didn't help and I think there is already an index on the id-field.
So, what I did and not works is now to find all human resources for the given tasks! And the tasks comes from Services and they are already fetched in the service model with "static fetchMode = [tasks:"eager"]"!
Controller-Code:
def listHumanResourcesFromTasks = {
def list = HumanResource.findAllByTasks(service.getTasks())
//and I tried also with an own HashMap but didn't work as well
}
I always get an error "org.springframework.dao.InvalidDataAccessResourceUsageException" with an SQL-GrammarException. But I really don't know why. The "service.getTasks()" objects are fully filled (as I wrote with fetchMode = [tasks:"eager"])...
It would be awesome if somebody could give me the winning hint.
Thanks a lot for your time.
Best wishes,
Marco

This sort of query isn't supported - you'd need to use HQL or a criteria query in general. But this particular one is easy since you have a bidirectional relationship. You can get all of the HumanResource instances for a collection of Tasks with this:
def resources = service.getTasks().collect { it.humanResources }.flatten() as Set
It needs to be a Set since the same HumanResource instance may appear multiple times so you need to condense the List into unique instances.

Related

Grails criteria duplicate association path error

I am trying to use aliases along with the normal association names in a criteria which is giving me "duplicate association path error" my classes are as follows
class FlightReservation{
Flight flight
User usr
String title
}
class Flight {
String flightNumber
Category category
}
class Category {
String name
}
Criteria query
FlightReservation.createCriteria().list(){
createAlias("flight", "flt", CriteriaSpecification.LEFT_JOIN)
flight{
location{
eq("name", "abc")
}
}
order("flt.flightNumber", "asc")
}
Now as i think about it, it seems obvious and perhaps a Hibernate limitation
so i want to know if there's an alternate approach to achieve this
I know i can use fetchMode to load the flight association
but eliminating alias from the query would make things difficult for order clause( which is going to be dynamic and nesting closures would make things ugly)
One might say why can't I use "flt" (alias) in both the places? Actually this other criteria which uses the nested closure instead of alias comes from some other part of the code and I am supposed to reuse that code.
Let me know, if the question isn't clear enough, any insights on this error would be really helpful.

Removing multiple items from a Grails One to Many relationship

I'm creating an application using Grails 2.2.4 and Java 7 (these are constraints I cannot change) and I run into an odd behavior when trying to delete multiple entries in a Many-To-Many hasMany Set.
I have a class named Sport that contains the following:
Class Sport{
String name
static hasMany=[category:Category]
static belongsTo = [Category]
}
And another one named Category:
Class Category{
String name
static hasMany=[sports:Sport]
}
Now when in my CategoryController I try to delete multiple Sport instances from sports, my code compiles and runs without errors, but for reason only one of the selected instances is actually deleted.
If I get a Sport list and a Category id from a form and try to run the following code on every objet in the list:
def categoryInstance = Category.get(idCategory)
def sportInstance = Sport.get(idSport)
if(sportInstance!=null){
categoryInstance.removeFromSports(sportInstance)
}
categoryInstance.save()
Only the last instance is deleted.
If I run
def categoryInstance = Category.get(idCategory)
def sportInstance = Sport.get(idSport)
if(sportInstance!=null){
categoryInstance.removeFromSports(sportInstance)
categoryInstance.save()
}
Only the first one is deleted.
Note that this code is run from within a for loop over the params.sport.toList() list.
My guess is that this is either due to the fact that my sports Set is somehow "changed" after the first deletion and therefore Hibernate can't find the next instance, or that my save method commits the first change then "forgets" the next.
Any advice on how I can delete more than one instance at a time?
A workaround is to wrap the code for deleting a single association in a block of withNewSession + withNewTransaction
Sport.withNewSession {
Sport.withNewTransaction {
//delete 1 association here
}
}
It's not very elegant but works. Beware of a potential performance impact, as this will likely have many database roundtrips.
I don't know why this problem occurs, and googling didn't help either.
Another solution = workaround is to explicitly map the relationship as SportCategory, which you can then delete like any other object with SportCategory.delete().

Grails table that links to itself

I would like to create a grails domain class that links to itself.
This related post suggests a solution but I can't get it to work: Grails domain class relationship to itself
For one thing I don’t understand what comparable does and would need to add a int compareTo(obj) method.
Adding the following to my code without implementing Comparable compiles, but grails crashes at runtime:
//NavMenu parent
SortedSet subItems
static hasMany = [subItems: NavMenu]
static belongsTo = [parent: NavMenu]
static constraints = { parent(nullable:true) }
Thanks in advance
When you're using SortedSet, a sort algorithm is internally executed, but it needs a sort criteria. You need to implement the Comparable interface because that is the standard way to provide a sort criteria to the internal algorithm.
If you don't need a specific order, you can delete the SortedSet subItems line and thus avoid implementing the Comparable interface.
If you don't want to use Comparable interface, maybe you should use List instead of SortedSet.
With a list you can keep objects in the order which they were added and to be able to reference them by index like an array.
This is an example from official docs:
class Author {
List books
static hasMany = [books: Book]
}

Grails per-query one-to-one eager fetching

Let's say you have face and nose, and you want to get the nose based on a faceId.
The Grails user guide tells you how to use mapping = { fetch:join } in a domain class to eagerly fetch the nose in one query whenever you fetch the face.
But I don't want to eagerly fetch all the time. I just want to do on this particular case to use one query instead of two. Can this be done on a per-query basis? Is there some way to do something like:
Face.get(faceId, [join:nose])?
Do you mean somthing link taht:
static fetchMode = [nose:'eager']
found here
Update:
You can solve the problem with a criteria query. Here you can set the fetch mode in the query:
import org.hibernate.FetchMode as FM
def c = MyDomain.createCriteria()
def results = c.list {
maxResults(10)
firstResult(50)
fetchMode("aRelationship", FM.EAGER)
}

What is the best way to declare sorted association in grails domain classes?

It seems that there are two different ways of declaring sorted associations in Grails :
Method 1 (see here) using default sort order
class Book {
String title
}
class Author {
static hasMany = [books : Book]
static mapping = { books sort: "title"}
}
Method 2 (see here) using SortedSet
class Book implements Comparable {
String title
int compareTo(obj) {
title <=> obj.title
}
}
class Author {
SortedSet books
static hasMany = [books : Book]
}
I am not sure which one to use and what is the difference (if any), pros and cons between using one against the other.
I would appreciate any clarification.
Thank you
I started to dig into how this all works and then found that method 1 is actually busted in current versions of grails (tested in both 1.2.1 and 1.3). When you actually try to retrieve an author and look at it's books, it throws an exception
There is an open defect for it (4089) which has been open for quite a while.
Here's the exception that gets thrown:
ERROR util.JDBCExceptionReporter - Column not found: BOOKS0_.TITLE in statement [select books0_.author_books_id as author1_0_, books0_.book_id as book2_0_ from author_book books0_ where books0_.author_books_id=? order by books0_.title]
If and when they finally fix it, the differences between the two methods are that in method one, sorting is done at the database level. As you can see in the exception above, GORM was trying to do an "order by books0_.title" which would use any database index on the book.title field and return the objects in that order.
The second method would sort the objects in memory at the time that they get inserted into the set (using the compareTo method that was defined).
Until the current bug is fixed, I'd use method 2 because it's the only thing that works. It should be fine for relatively small collections of things. After it's fixed, I'd potentially prefer method 1 as the database should be quicker at doing the sorting with an index on the sort field.

Resources