I have a Grails class that both has got a many-to-many relationship (with the other side being the owner) as well as a n:1 relationship.
I could not find an answer on the web how to put the ownership into the belongsTo clause.
This is the code:
class PanelType {
static hasMany = [elements: LabValueType]
}
class LabValueType {
static belongsTo = [labUnit: LabUnit]
// This is what would be needed to have a bidirectinal n:m relationship
// belongsTo = PanelType
// static hasMany = [panelTypes: PanelType]
}
If I leave it like this, the application builds the database correctly, but I won't be able to navigate from LabValueType to PanelType.
I found one answer (from 2008!) that said I should write:
static belongsTo = [PanelType, LabUnit]
BUT this way, the field lab_unit_id is not created in the database, so it does not seem to be correct.
I have found that I can work around this problem by declaring the relationships like this:
LabUnit labUnit
static belongsTo = PanelType
static hasMany = [panelTypes: PanelType]
But somehow it is not really 100% satisfying.
Related
What is the difference between
static belongsTo [author:Author]
and
static belongsTo = Author
Lets consider two domain class.
Class Author{
String name
}
Class Books{
String name
static belongsTo = Author
}
When static belongsTo = Author is kept in Books domain, it have no effects on db. However, static belongsTo = [author : Author] creates a backreference to Author class and also there is author_id column in db. So, what actually using static belongsTo = Author alone does.
This is expalined in grails docs(http://grails.github.io/grails-doc/latest/ref/Domain%20Classes/belongsTo.html).
Also, what is the difference between using following two :
Class Books{
String name
static belongsTo = [author : Author]
}
Class Books{
String name
Author author
}
static belongsTo = [author : Author] is used only for cascading purposes, Is it true or does it have different use cases.
Can anyone explain these in detail without relating it to hasOne or hasMany. Thanks in advance.
Using belongsTo without a back-reference is necessary for many-to-many associations. For example, lets assume you have the following domain classes:
class Book {
String name
Author author
static hasMany = [categories: Category]
}
class Category {
String name
static hasMany = [books: Book]
}
If you try to use them as-is you'd get an exception like this:
No owner defined between domain classes [class Book] and [class Category] in a many-to-many relationship. Example: static belongsTo = Category
The solution is to make one of the domain classes the owner of the many-to-many association. Using my example, I think it makes more sense to make the Category the owner. However, a back-reference would not work because there could be multiple Categorys. So, this is where a belongsTo without a back-reference comes in:
class Book {
String name
Author author
static hasMany = [categories: Category]
static belongsTo = Category
}
If you use static belongsTo = [author: Author] then a property named author of type Author is added to the class as a back reference. With static belongsTo = Author that does not happen.
Is it possible to have a domain class that belongs to multiple domain classes with back reference? For instance:
class Person {
List<Book> books
static hasMany = [books: Book]
}
class Organization {
List<Books> books
static hasMany = [books: Book]
}
class Book {
def owner // what's the type?
static belongsTo = [Person, Books]
}
A Book can belong to a Person or an Organization, but not both.
Person and Organization have separate sequence IDs.
The solution I came up with is:
class Book {
Long ownerID
String ownerClass
static belongsTo = [Person, Books]
static transients = ['owner']
static constraints = {
ownerId(nullable:false, blank:false)
ownerClass(nullable:false, blank:false)
}
public BookOwner getOwner() {
grailsApplication.getArtefact("Domain", ownerClass)?.getClazz()?.get(ownerId)
}
}
where BookOwner is an Interface implemented by Person and Organization. So calling a bookInstance.owner will return a Person or Organization instance, both BookOwner.
My solution works well, but it doesn't feel right - a sure sign that I am not fully understanding what I'm doing. What's the best way to implement this? Should I completely give up on having the extremely convenient back reference?
Thank you
I guess, you should have made Owner superclass. Grails will create Owner table with field class meaning child class names (in your case: Person, Organization).
I am new to Grails.
Can I use "hasOne" or "hasMany" without using "belongsTo" to another domain-class?
Thanks in advance.
Yes, you can. See examples in Grails doc: http://grails.org/doc/2.3.8/guide/GORM.html#manyToOneAndOneToOne
hasMany (without belongsTo) example from the doc:
A one-to-many relationship is when one class, example Author, has many
instances of another class, example Book. With Grails you define such
a relationship with the hasMany setting:
class Author {
static hasMany = [books: Book]
String name
}
class Book {
String title
}
In this case we have a unidirectional one-to-many. Grails will, by
default, map this kind of relationship with a join table.
hasOne (without belongsTo) example from the doc:
Example C
class Face {
static hasOne = [nose:Nose]
}
class Nose {
Face face
}
Note that using this property puts the foreign key on the inverse
table to the previous example, so in this case the foreign key column
is stored in the nose table inside a column called face_id. Also,
hasOne only works with bidirectional relationships.
Finally, it's a good idea to add a unique constraint on one side of
the one-to-one relationship:
class Face {
static hasOne = [nose:Nose]
static constraints = {
nose unique: true
}
}
class Nose {
Face face
}
Yes you can, but it behave differently
class Author {
static hasMany = [books: Book]
String name
}
class Book {
String title
}
In this case if you delete Author the books still existing and are independent.
class Author {
static hasMany = [books: Book]
String name
}
class Book {
String title
static belongsTo = [author: Author]
}
In this other case if you delete the Author it will delete all the books pf that author in cascade.
Many-to-one/one-to-one: saves and deletes cascade from the owner to the dependant (the class with the belongsTo).
One-to-many: saves always cascade from the one side to the many side, but if the many side has belongsTo, then deletes also cascade in that direction.
Many-to-many: only saves cascade from the "owner" to the "dependant", not deletes.
http://grails.org/doc/2.3.x/ref/Domain%20Classes/belongsTo.html
yes very easy like a class defintion but only specify hasMany but no need for hasOne
class Student {
String name
User userProfile
static hasMany =[files:File]
}
class User {
String uname
Student student
}
class File {
String path
Student student // specify the belongs to like this no belong to
}
Done!!
Currently i'm getting the following error :
No owner defined between domain classes [class mp.ra.Classgroup] and [class mp.ra.Event] in a many-to-many relationship.
The domain classes are set up as followed,
The event class:
class Event {
static hasMany = [classgroups:Classgroup]
static belongsTo = [eventgroup:Eventgroup,classgroup:Classgroup]
static constraints = {
eventgroup nullable:true
}
And the Classgroup
class Classgroup {
static hasMany = [courses:Course,events:Event]
static constraints = {
courses nullable:true
}
An Event can have multiple classgroups and a classgroup can have multiple events.
I use the belongs to property so i don't see why i'm getting this error.
EDIT: I changed The Event class and the error is gone , i dont know if this is a good solution
class Event {
Eventgroup eventgroup
static hasMany = [classgroups:Classgroup]
static belongsTo = [Eventgroup, Classgroup]
static constraints = {
eventgroup nullable:true
}
In Grails many-to-many mapping we should define an owner class between both of the associated classes.
As earlier you defined :
belongsTo = [eventgroup:Eventgroup,classgroup:Classgroup]
with this GORM tried to create a column with classgroup name under Event table, but for many-to-many association with classgroup, database should suppose to have third table to have multiple records for many-to-many associations between Event and Classgroup. So was giving such error.
Hence later when you mention :
belongsTo = [Eventgroup, Classgroup]
it worked as it just got owner information.
So here Classgroup would be the owner of association, as Event belongsTo Classgroup.
Hope this helps. Thanks.
These are my domain classes:
class Game {
static hasMany = [players: User]
static belongsTo = [owner: User]
}
class User {
static hasMany = [games: Game]
}
If I try to use them as they are I get No owner defined between domain classes. So I need to set the owner of the relationship. Adding static belongsTo = Game to User causes Domain classes cannot own each other in a many-to-many relationship.
The only other option I can think of is to add static belongsTo = User to the Game class but I already have a belongsTo there.
How do I model this?
class Game {
User owner
static hasMany = [players: User]
static belongsTo = User
}
class User {
static hasMany = [games: Game]
}
You will have to specify one side of the relationship, as the owner, by doing this you will make User domain class as the owner of the many to many relationship.
The belongsTo field controls where the dynamic addTo*() methods can be used
from. we’re able to call User.addToGames() because Game belongsTo
User. we can’t call Game.addToPlayers().
Try this:
class Game {
User owner
static hasMany = [players: User]
static belongsTo = User
}
maybe it would be better not to use "belongsTo" at all? I mean using simple field reference like
class Game {
User owner
static hasMany = [players: User]
}
FYI,
I would be careful with using "owner" field name, it might cause problems when used somehow in a closure which has its own "owner" reference (e.g. in criteria builder)
I know it caused problems back in grails 1.3.X, I don't know if it's still the case
try this:
class Game {
User owner
static hasMany = [players: User]
static belongsTo = User
}
class User {
static hasMany = [games: Game, owns: Game]
static mappedBy = [games:'players', owns: 'owner']
}
this settings work for me. And here is a good thread for mappedBy: GORM mappedBy and mapping difference