Removing association from M:N relationship when deleting an entity - grails

In my domain I have a many-to-many relationship. The problem is that GORM forces me to define owner entity but I don't think that either side "owns" the relation.
class User {
String username
String password
static hasMany = [organizations: Organization]
static belongsTo = Organization
static constraints = {
}
}
class Organization {
String name;
static hasMany = [members: User]
}
In this case I'm obviously not allowed to delete User who is in some organization (because Organization "owns" the relation). I would like to be able to delete both entities and on delete simply remove the relation (row from user_organization table). Is it possible or do I have to write this logic myself (if so, what would be the best way to implement this)?

You are allowed to delete both sides of the relationship, no matter who is the "owner". The belongsTo just applies the proper cascading so you don't have to.
In your example if you want to delete a user you first have to remove the relationship. So, in order to delete a user you do:
organization.removeFromMembers(user)
user.delete()
And if you delete an organization, since it is the "owner", you just don't need to use removeFrom*.

Related

House belongsTo Owner?

Wondering if "belongsTo" is write way to represent an ownership relationship where there is always a parent object, but the parent may switch.
ie if owner domain is
class Owner {
String name
}
Should House be:
class House {
String address
Owner owner
}
or
class House {
String address
static belongsTo = [owner: Owner]
}
What I want to achieve is bi-direction 1:1 where I can either access owner.house or house.owner and ability to change the owner without without deleting the old owner.
without deleting the old owner. ?
So you have two choices - by far the easiest and where your current method is actually wrong should be Should House be: maybe this?
class House {
String address
static hasMany = [owner:Owner]
Owner currentOwner
}
With the relationships as it is, you are saying a house has many owner's. So owner1 owner2 .. and it also has a current Owner which is Owner itself.
Each time you add a new entry you add it to the owner collection so house.addToOwner(owner) and you then set the last/latest update of currentOwner=owner.
If you want to navigate throw both entities, and the relation is 1:1 you can use hasOne
class Owner {
String name
static hasOne = [house: House]
}
class House {
String address
static belongsTo = [owner: Owner]
}

Grails 3 hasOne nullability issue

While migrating an existing app from Grails 2.5 to 3.1, I ran into an odd issue with a bi-directional one-to-one relationship.
Imagine a simple model with a User and Employee objects. A User represents a generic user account. Not all users are Employees but all Employees are Users. Moreover Employees have references to managers, supervisors, etc (also User instances). User is the owning side of the relationship.
class User {
Employee employee
static mappedBy = [employee: "user"]
static hasOne = [employee: Employee]
static constraints = {
employee(nullable:true)
}
}
class Employee {
User user // represents employee's own account, a bi-directional one-to-one
User supervisor // represents a supervisor
static belongsTo = [user: User]
static constraints = {
user(unique:true)
supervisor(nullable:true)
}
}
The trouble after upgrading to Grails 3 is that in the create mode, this results in supervisor_id column of employee table being generated as NOT NULL, whereas in Grails 2 it was nullable as expected (with only user_id being NOT NULL).
I tested this with Grails 3.1.12 and 3.2.0, getting the same behavior with both. Am I doing anything stupid in my domain class declarations? I've tried multiple mappings to achieve the same behavior as in Grails 2.5 without luck. In some cases I'm even getting a foreign key on both sides of the relationship...
I don't know why your code was working with previous version of Grails, but it is wrong.
When you use hasMany and belongsTo, it is not necessary to define other property in the child object, and you don't need also to use the mappedBy property on the parent, and the same with the parent (property employee at User)
Grails doesn't need anything else to know which is the bidirectional property on both classes, and the constraint user(unique : true) neither.
So your classes should look like this:
class User {
static hasOne = [employee: Employee]
static constraints = {
employee(nullable: true)
}
}
class Employee {
User supervisor // represents a supervisor
static belongsTo = [user: User]
static constraints = {
supervisor(nullable:true)
}
}
It could be nice to know how is your DB structure. But in this way all foreign keys are stored in the employee table. But of course you could navigate from both entities. If you have different structure you could map your current database with this model. See this
employee.user
user.employee

Grails(GORM) - Multiple many-to-many and cascade delete

Let's say i have 3 domain classes:
class Book {
static belongsTo = [Author,User]
static hasMany = [authors:Author,usersWhomReadThisBook:User]
String title
}
class Author {
static hasMany = [books:Book]
String name
}
class User {
static hasMany = [booksRead:Book]
String name
}
belongsTo defines a cascading relationship so deleting a parent will delete all objects that belong to it.
Question is: when I delete a User does it cascade up and delete the Books the user have read? Even if it still belongs to an existing Author? Or does it only delete from the join table?
The documentation is not clear on this use case.
Your question is:
When I delete a User does it cascade up and delete the Books the user have read? Even if it still belongs to an existing Author? Or does it only delete from the join table?
The answer is:No deletes are not cascaded for many to many,here if we delete the user only it will be deleted because the books is associated with other class Author.

How to specify Association in Grails

I have got a domain class Track
class Track{
static belongsTo = [createdBy: User, modifiedBy: User, Course]
}
But its giving me error, Finally i dont want to have course object[course: Course] but only have to specify that it belongs to Course [Course]. How to do this
I think you are using the GORM associations a bit too extensively. belongsTo indicates ownership, and the GORM associations, in general, indicate more about the cascading relationship between objects than anything else.
If you only want to associate User with your Track, you just need to have the createdBy and modifiedBy fields, which don't need to be in any special sort of association. Then you would have static belongsTo = [Course] to show that the Course owns the Track, meaning that if you deleted the Course, that the Track would get deleted as well.
Here's the class I think you are looking for:
class Track {
User createdBy
User modifiedBy
static belongsTo = [Course]
}

Grails/GORM: The meaning of belongsTo in 1:N relationships

In an ordinary one-to-many mapping the "one"-side is the owner of the association. Why would anyone use the belongsTo-mapping for such a mapping? Am I missing some side-effect of specifying belongsTo?
In other words: what are the effects of specifying a belongsTo-mapping in GORM vs. not specifying it?
Whether to specify belongsTo depends upon the type of referential action you want.
If you want Grails to do On Delete, CASCADE referential action, then DO specify belongsTo. If you want Grails to do On Delete, RESTRICT referential action, then DON'T specify belongsTo.
e.g.
// "belongsTo" makes sense for me here.
class Country {
String name
static hasMany = [states:State]
}
class State {
String name;
// I want all states to be deleted when a country is deleted.
static belongsTo = Country
}
// Another example, belongsTo doesn't make sense here
class Team {
String name
static hasMany = [players:Player]
}
class Player {
String name
// I want that a team should not be allowed to be deleted if it has any players, so no "belongsTo" here.
}
Hope this helps.
Specifying belongsTo allows Grails to transparently cascade updates, saves and deletes to the object's children. Without belongsTo, if you attempt to delete a master record, you'll end up getting a foreign key violation if it has any details it owns.

Resources