Grails self referencing domain class surprising save result - grails

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.

Related

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 save() method bug

For example I have entity person saved in db with the name John and id 1 then:
def person = Person.get(1)
person.name = 'Maria'
person.save()
//after that name still will be John
//but if I save one more time than name be Maria
Addition information is that my domain have inside service, and method that work with this service.
I don't now in what is a problem, maybe somebody had already this situation.
It's not flushed at this moment, changes kept in memory for a while. If you need to force Grails to update DB exactly at this moment, add flush: true parameter:
person.save(flush: true)

Prevent duplicate entry for save smartly in grails

I have a domain named thana where I put all the thanaName. But I don't want to save any duplicate name. There may be a lot of way for doing this but which will be much smarter I don't know. Can anyone please help me on this. any example or source code will do the work perfectly. thanks in advance for watching the question.
This sounds like the prefect use case for the unique constraint.
class MyDomain {
String name
OtherDomain related
static constraints = {
name unique: ['related'] // each instance must have a unique name per related
}
}
Edit
Updated based on question in comment. The above will ensure that name is unique for each related. So, for example if MyDomain A has a related instance id of 1 and a name of "Test" no ohter instance of MyDomain with the same related instance can have the name of "Test". However, MyDomain B which has a rleated instance id of 2 can have a name of "Test" since the unique is per "related" in the above example.

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