I have a composition pattern where a parent object has a list of child objects, e.g., Order and LineItem.
It behaves similar to cascading with delete orphans, but the child objects are #Embeddables instead of #Entities, and don't get their own IDs - they're always managed through their parent object.
In JPA I could do something like this to ensure that whenever I save an Order, the collection of LineItems synchronize, including deleting removed items:
public class Order {
#ElementCollection
#CollectionTable(...)
private Set<LineItem> items;
}
In Grails, what's the equivalent?
I can do hasMany with cascade all-delete-orphan but would prefer if there were a similar way for the child objects to not have their own IDs (basically, not be entities).
You can use static embedded in Order. Refer this.
Related
I have a simple one-to-one relation between two Grails entitites like this:
class Parent {
static hasOne = [child: Child]
}
class Child {
Parent parent
}
The problem is that when loading the parent entity (e.g. using def parent = Parent.first()), the child is selected from the database simultaneously with a second query as can be seen in the hibernate debug log, although according to the documentation single-ended associations should be fetched lazily by default. Also using the lazy: true mapping configuration from the mentioned docs apparently doesn't change anything.
The situation is the same when using static belongsTo = [parent: Parent] in the child instead.
This issue (currently open) describes the same behavior.
So is there any way to stop the child association to be fetched?
Optimally, I imagine it should be either fetched using a single select with join or not selected at all (or upon first access of the child), preferrably controlled by a switch or using a fetch join in a HQL query.
Optimally, I imagine it should be either fetched using a single select
with join or not selected at all (or upon first access of the child),
preferrably controlled by a switch or using a fetch join in a HQL
query.
It can be made to be fetched with a single select.
The issue at https://github.com/grails/gorm-hibernate5/issues/136 links to the sample project at https://github.com/alanbino/gorm-hasone. I forked that to https://github.com/jeffbrown/gorm-hasone and made changes.
The commit at https://github.com/jeffbrown/gorm-hasone/commit/32cb943cbc27deb5ebf164aa1461b3956285fe1d demonstrates how to get the data retrieved in a single select. That commits configures the join...
static mapping = {
table 'a_parent'
id generator:'assigned'
aChild fetch: 'join'
}
The subsequent commit at https://github.com/jeffbrown/gorm-hasone/commit/575ae2152767ded30686cb2e3daa70519f03c8ba isn't really related to the issue here, but eliminates a number of complexities that don't relate to the issue and eliminating those makes it easier to evaluate the code. Ignore that if that is a distraction.
I have mapped two tables on Domain classes, say:
Parent table that hasMany of the table Child.
Child table that belongsTo a table Parent.
I want point out that there is no specific foreign keys explicitly declared on the database, rather it is declared on the GORM's mapping. But here's the catch: There are special types of Child that are orphans- that is, doesn't have their Parent table counterparts. Everytime I access these orphans via a valid Child.findById(), an error shows:
Message: No row with the given identifier exists
that is not present when accessing a non-orphan Child. I had marshalled these Domain tables already in such a way that everytime a Child is parsed as JSON, it will have a property called parents which is an array of Parent and the other way around. It is already working- except for these orphans' case.
How should I fixed this? Should I remove their GORM join, since they are not actually joint on the database side?
I'm assuming you have domain classes that look like this:
class Parent {
static hasMany = [children: Child]
}
class Child {
static belongsTo = [parent: Parent]
}
That's a bi-directional one-to-many association. GORM expects the child table to contain a foreign key to the parent, and the child can only exist if it has a parent.
One way to allow orphan children is do to as you suggested: remove the gorm associations. Another way is to remove the belongsTo to create a uni-directional association. That way a child can exist without a parent.
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.
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
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.