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.
Related
as part of an upgrade from 2.4 to Grails 5, I've encountered an oddity where when I attempt to access a particular field in a domain, I get a SQL exception because the back reference _id column is not found.
My model is as such:
class Parent {
Child firstChild
Child secondChild
}
class Child {
static belongsTo = [parent:Parent]
}
My understanding is there will be a parent property added to the Child class, but no back referencing column will be created in the table unless I add a hasOne declaration to the Parent class. Which is what I want, and what used to work. This also works if there is only one Child, but the problem starts when I add the secondChild.
However when I have an instance of a Parent, e.g. Child childInstance and I access the parent property, then it's firing a SQL Syntax exception Unknown column 'parent_id' in 'field list'
Since Grails 2.4 is there something different we need to do to correctly handle this relationship and not require any parent_id in the child table
Thanks.
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.
I have created Child domain and made 2 parents to it. One parent I declared as a field. And another parent I declared with the help of belongsTo constraint.
package multipleparentsgrails
class Child {
Parent2 parent2
static belongsTo = [parent1: Parent1]
static constraints = {
}
}
Is there any difference between these ways?
How to eliminate differences? Can I have both belongTo and a member? Can I add cascading having a member?
belongsTo plays significant role in parent child relationship. Here the class specified in belongsTo is the Parent / Owner of the relationship.
Following could be some comparison in normal has a and belongs To:
belongsTo marks the referenced class as Owner of the relationship while same is not true in case of has a
You don't need to worry about hibernate related cascading as relationship automatically will handle that i.e. you may specify cascade type but need not to give implementations otherwise in case of has a you have to use GORM DSL like stuff.
Last but not least belongsTo also makes it mandatory to specify relationship owner while in case of has a constraints are the barriers.
Last but not least it might also make difference in gsp scaffolding as well but not sure about it.
Hope it Helps!
Yes, belongsTo defines cascading. If parent1 is deleted, so is child since it belongsTo parent1. If parent2 is deleted, Grails won't delete child automatically for you.
So, in this case, stating that a child belongsTo a parent wouldn't be very children-friendly :-)
You can define belongsTo in a few different ways, which allows you to define it on separate fields or to declare new fields. See the Grails documentation for further details, they have good examples of its use.
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.
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.