Is there anyway to perform a "deep save" in Grails? - grails

In my service I create a "root" object which has associations to many objects which in turn have associations to many more objects and so on. Once the root object is completely built and ready to be saved I would like to call save on the root object and have all associated objects all the way down be saved as well. Right now I have a recursive method called deepSave which does this. Is there a better way?

If you use belongsTo GORM automatically defines the cascading for you. This means: If A belongsTo B then A will be saved when B is saved. However, it is possible to define cascading without using belongsTo (if this does not fit to your domain model):
class Author {
static hasMany = [books: Book]
static mapping = { books cascade: 'all-delete-orphan' }
}
You should have a look at the cascade property provided by GORM. Additionaly the hibernate documentation provides more detailed information.

Related

Grails: Simple hasMany relation create more tables than necessary

Hi I have a simple problem.
My domain class is like this:
class Example {
long seq
hasMany = [example_array: ExampleData]
long count
}
class ExampleData {
String type
long description
static belongsTo = Example
static constraints = {
}
}
This results in 3 tables, like a many to many relation.
Why is this?
Thanks
The reason for the extra table is that you've modeled the relation only in one direction - an Example can access its ExampleData instances via the example_array Set that's added to your class bytecode because of the hasMany property, but an ExampleData instance has no way to reference its owning Example.
You added a belongsTo property, but only specified the class name. That's sufficient to configure ownership, cascaded deletes, etc. but doesn't provide a property in the class to access the Example instance.
If you change it to the other supported syntax it will work as you expected:
static belongsTo = [example: Example]
Here example will end up being the name of an Example property (and you can change it and/or example_array to any valid property name), which is basically the same as declaring
Example example
Now that both sides can access the other, the relationship is bidirectional and you no longer need the third table. That's because a 1-many is typically implemented using a foreign key in the child table, in this case in the table for ExampleData that points to the table for Example. That wasn't possible without a property in the class to wire up to that column, so the join table was necessary.
I believe that you have to map the BelongsTo, like this:
static belongsTo = [example:Example]
Hope it helps :)
From the definition of hasMany Grails will, by default, map this kind of relationship with a join table.That join table is the 3rd table you mentioned.No need to worry about that.
Well the one-to-many relationship is constructed by having additional table (i.e. Example_ExampleData) containing two columns each id fields from tables of the entities forming the relationship(i.e. Example and ExampleData).
The newly added table is child to parent tables – Example and ExampleData.
So in your case when you run your application the 3rd table gets created by Grails by default as your table relationship falls under the one-to-many relationship.

How to make a domain class that belongs to one of a number of possible classes in Grails

I want to create a Comment class to allow my users to add comments to a number of different things.
class Comment {
User author
String text
static belongsTo = [post:Post, user:User]
static contraints= {
post(nullable:true)
user(nullable:true)
}
}
When I try and create a comment object using a post and without a user, i get the error "Property [user] of class [class Comment] cannot be null".
What is the best way to create a class that can belong to one of a number of different classes?
The best solution is to use a plugin like commentable.
However, if you want to roll your own solution then you need to understand that making something BelongTo another object makes it a required relationship. Thus it can't be null. Remove the belongs to and do a uni-directional one-to-many relationship. See the Grails documentation on modeling relationships.

Grails: Delete relation Domain

I want to asked about my project.
I Have Two Domain like this
I suggest you to look in the GORM documentation. You have some ways to declare your relationship between classes, and depending on them the delete will be cascade or not.
This behavior is explained in "6.3.3 Understanding Cascading Updates and Deletes".
Whether it is a one-to-one, one-to-many or many-to-many, defining
belongsTo will result in updates cascading from the owning class to
its dependant (the other side of the relationship), and for
many-/one-to-one and one-to-many relationships deletes will also
cascade.
So you should consider declaring hasMany and belongsTo, to enable the cascading deletes.
class User {
// Group details should not be referenced here
}
class Group {
String Name
String Description
GroupDetails gd
}
class GroupDetails {
User user
static belongsTo = [group:Group]
}
In this case if Group will have a child GroupDetails then when you delete Group, child entity(ies) will also be deleted.
Have a look at first example in grails docs: http://grails.org/doc/2.2.x/ref/Domain%20Classes/belongsTo.html
Also as Sérgio Michels there are more ways to make it work.
example: https://github.com/aprudnikovas/testGrailsOneToOneCascade

Should removeFrom* method remove child item from a DB or it should just remove the parent-child relation?

The question is in the subj.
Currently, the behavior I observe is that when I call Parent.removeFromChilds(child), child is not removed from my DB (i.e. I can find it with Child.findBy...(args)).
I'm curious if it's the correct behavior. If yes - what's the best way to remove both relation and child within one transaction?
If no - what may I do wrong?
By default, deletes cascade if you delete the owning side of a one to many. If you just remove the child, it will not delete. You can change that by specifying the custom cascading behavior of 'all-delete-orphan' on the owning side of the relationship. From the Grails doc:
class Person {
String firstName
static hasMany = [addresses: Address]
static mapping = { addresses cascade: "all-delete-orphan" } }
Update
Part 2 of GORM Gotchas has a really good breakdown of the not-so-obvious addTo and removeFrom behavior. I think it contains the exact information you're looking for.

How to prevent cascade delete for bidirectional associations?

I'd like to know if it's possible to delete parent objects in a bidirectional 1:N association without a cascade delete. According to
http://grails.org/doc/1.0.x/guide/5.%20Object%20Relational%20Mapping%20%28GORM%29.html
...in a unidirectional relationship the parent end gets mapped with a 'save-update' and the child end with a 'none'. I've tried these settings for the bidirectional relationship, but not very surprisingly it didn't work. Specifically:
class Personnel {
...
}
static hasMany = [projectlead:Project, projectmanager:Project]
static mappedBy = [projectlead:'leaddeveloper', projectmanager:'projectmanager']
static mapping = {
projectlead cascade:'save-update'
projectmanager cascade:'save-update'
}
And here's the project class:
class Project {
...
}
static belongsTo = [leaddeveloper:Personnel, projectmanager:Personnel]
static mapping = {
leaddeveloper cascade:'none'
projectmanager cascade:'none'
}
I'd rather not redesign my application (by removing the "belongsTo" from the Project class) if there's a solution to this: the navigational access from both ends is very convenient and I don't have too much instances on the project end.
Also, if there's a way to implement this, it would be interesting to know, what happens with those active mappings afterwards, can I set them (or will they be set) to "null" for instance?
Appreciate any inputs on this matter.
By reading your question, I think that you want to delete "Personnel" object but leaving his "projects" untouched. Sadly, this can't be done with your current implementation. A "belongsTo" relationship means that every child object must has a Parent object. If you delete the Parent, the orphan will be deleted as well.
Another option that you could try without modifying too much the design is "marking as deleted". Add a "deleted" field in Personal, and in case you want to delete someone, just mark him as deleted. This will help you keep the historical data of projects, even after the project manager left.

Resources