How do hasMany and hasOne work in Grails? - grails

I am having problems defining one-to-one and one-to-many relationships with domain classes.
I have the following domain classes
class Team {
static hasMany = [players: Player]
static hasOne = [coach: Coach]
}
class Person {
String name
}
class Player extends Person {
}
class Coach extends Person {
}
So my questions are:
1- Do I need to declare a variable team in Player and in Coach ?
2- Do I need to declare a belongsTo as well?
3- Considering the above classes, is it preferable to use hasOne?
Thank you.

There is a slight mistake with leebutt's answer.
The cascade is the other way around: if your coach/player has belongsTo set to Team, then a deletion of the team would cascade and delete the coach/player as well.

Only if you want to be able to easily navigate via player.team and coach.team
Depends on whether or not you want updates/deletes to cascade. I'd think not, as deleting a coach or player should not delete the team or vice versa?
hasOne looks to make sense for the team > coach relation, however it doesn't exist in Grails 1.1.1 or below. It might be in 1.2 (but it's not in the ref guide).
cheers
Lee

Related

Grails self referencing domain class surprising save result

I have a self-referencing domain class like this:
class Person {
String name
Person father
Person mother
}
I have no hasMany or other constraints on father or mother
I have a service that inserts new entries from a .csv file as follows
Person father = Person.findBy(newPersonFatherName)
Person mother = Person.findBy(newPersonMotherName)
Person newPerson = new Person(
name: newPersonName,
father: father,
mother: mother)
newPerson.save()
What happens when this is executed is the maternal grandmother and paternal grandfather are both set to the same instance as newPerson.
I can make this go away by inserting the following two lines before the save()
Person pgf = father.father
Person pgm = father.mother
Person mgf = mother.father
Person mgm = mother.mother
I guess the whole thing is somehow related to cascading saves but I'm unable to really understand the problem, and I'm reluctant to leave such a poorly understood solution in place in the code.
Can anyone help? Thanks in advance!
It seems this problem has gone away somewhere between Grails 2.5.5 and Grails 3.3 so I'm going to mark this as answered and solved.

GORM one to one relationship while keeping existing entries

After going over GORM's documentation, I've figured out how to create one-to-one relationships between objects. However, I haven't figured out how to go about enabling my desired relationship. The relationship I'm trying to create acts as a one-to-one, but keeps previous row entries for historical purposes.
For example, a Car can have multiple owners throughout its lifetime. If I have Car and Owner domain objects, how can I specify that the most recent entry in the Owners table for a given Car ID is the correct one?
There are lots of different ways to model this. IMO, one of the most flexible approaches is:
class User {
String name
static hasMany = [ownerships: Ownership]
}
class Car {
String name
static hasMany = [ownerships: Ownership]
}
class Ownership {
Date start
Date end
static belongsTo = [owner: User, car: Car]
}
For example, when Ann sells her car to Bob, we set the end-time of Ann's Ownership record to the time of sale and save a new Ownership record for Bob with the start-time set to the time of sale.
If getting the current owner of a car is an operation we frequently need to perform, we could add a currentOwner method to Car
class Car {
String name
static hasMany = [ownerships: Ownership]
Ownership currentOwner() {
// depending on how this method is used, you might want to
// return the User instead of the Ownership
Ownership.findByEndIsNullAndCar(this)
}
}

Grails - associations by referencing id only

I'm trying to employ Domain Driven Design into my application, and in order to limit deep traversal between aggregate roots, the advice is to associate them using only their identities. Say I have the following domain classes,
Person
class Person {
Integer age
String name
}
and PhoneBill
class PhoneBill {
// reference to Person
Long accountHolderId
BigDecimal amount
}
As it is, this setup can already work. However, I want to add foreign key constraint to accountHolderId just to make sure any value set to it already exists in the data store. The official Grails docs don't seem to cover this.
Assuming your Person object still has an id, you can add a custom validator which returns an error if the id isn't valid.
class PhoneBill {
// reference to Person
Long accountHolderId
BigDecimal amount
static constraints = {
accountHolderId validator: {
!Person.exists(it) ?: 'your.custom.error.message.key'
}
}
}
Note that .exists() is only available for Grails 2.3.x, I believe. If you're using an older version, you can call .get() just as well.

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 Many-To-Many - Problems of dynamic finder

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.

Resources