How to prevent cascade delete for bidirectional associations? - grails

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.

Related

Is there anyway to perform a "deep save" in 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.

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.

Grails hasOne unidirectional

Currently I'm having some trouble, creating an unidirectional relationship in Grails.
I have a class Toilet with an Attribute Address.
This Address is a seperate class.
The Address can - theoretically - still exist, if the Toilet-Object, which the Address is associated with, gets deleted.
The toilet will stay, too, if the address gets deleted.
GORM's hasOne is not what i need, because it creates a bidirectional relation.
Defining an attribute of the type class only results in a non-persisted Address (despite it's own table) - that means, the association of the Address to the Toilet-Object doesn't exist
I'm not really familiar with these kinds of relationships, so I would really appreciate a solution or another way to accomplish my goal
Hope my problem is clear - if not comment, and I will try to add further explanations
taken from
http://grails.org/doc/1.0.x/guide/5.%20Object%20Relational%20Mapping%20(GORM).html
5.3.3 Understanding Cascading Updates and Deletes
It is critical that you understand how cascading updates and deletes work when using GORM. The key part to remember is the belongsTo setting which controls which class "owns" a relationship.
Whether it is a one-to-one, one-to-many or many-to-many if you define belongsTo updates and deletes will cascade from the owning class to its possessions (the other side of the relationship).
If you do not define belongsTo then no cascades will happen and you will have to manually save each object.
So.....if you do not use belongsTo then if you manually save each object you should not have a problem.
If the address on Toilet is a simple association without a hasOne or belongsTo mapping, then no operations will be cascaded.
That means you'll have to save the address, assign it toilet.address, and save the toilet.
Found the solution.
What I left out, was the implemenation of an interface in the Toilet class.
The problem was (as a reminder) that the relationship of the address within the toilet class wasn't saved to the database.
This was a problem of the interface itself - in this interface, getters and setters were defined and had to be implemented (the way an interface works - obviously). The problem here was, that the setter of the Address-Attribute expected the Type IAddress.
I overloaded the setter to also receive a parameter of the type Address.
With this change, the relationship between Toilet and Address is saved correctly to the database - the ID of the Address is saved in the table of the Toilet.
I think the definition of the setter is just a mistake (i have no influence on the interface), but with this workaround i can get it to work anyways
Hope this explanation helps others too.
Why not have a class which models the association ?
class ToiletAddress {
Toilet toilet
Address address
...
}
... and then simply wrap your logic into a service where you assign addresses to toilets, and delete toilets or addresses.
Using constraints you can define what kind of association it is. eg 1-1, 1-n (both sides), and n-m
static constraints = {
address unique: ['toilet']
toilet validator: {val, obj -> ... }
}

Grails - Preventing a recursive one-to-many relationship

I have the following domain class in Grails:
class TreeNode {
String name
String description
static hasMany = [childNodes: TreeNode]
}
What is the most idiomatic Grails way of ensuring that an instance of TreeNode cannot have itself as a child? Can I do this as a constraint in the domain class, or should I be writing custom code in the Save action on the TreeNodeController?
Do it as a custom constraint.
static constraints = {
childNodes(validator: {value, obj, errors->
if(value.contains(obj) {
errors.rejectValue('childNodes', 'Cannot contain self')
}
}
}
The answer depends on how deep you want to check within the children. If you are only worried about the immediate children, then the code from #Tiggerizzy should work just fine.
If on the other hand you want to verify that the node isn't an immediate or deep child in your tree, then the logic should be pulled out of validation and placed within a Grails Service class. This would offer at least two benefits:
If other properties in the node change, but not the structure of the tree, you can skip the children check validation and save yourself the extra processing time when validating.
If you are validating from near or at the root of the tree, then verifying all of the sub-children would be a longer process for a large tree, involving a lot of database work. By doing this work in a Service class you gain the Service's transactional nature, which will roll back any database changes on an unhandled Exception such as in an optimistic lock situation with another thread.

Resources