How to define Grails Domain Objects Relationships - grails

Hi I am new to Grails and I would like to seek your expert advise on how to define the domain class in Grails for the following scenario:
A buyer can buy many items
A delivery can contain many items, not necessary all the items the buyer has bought, as some items will be delivered at a later time.
A delivery cannot contain any new items that the buyer hasn't purchased.
So the following is the relationships between them:
One buyer can have many items
One buyer can have many deliveries
One delivery can have many items
I have defined the domain classes as such; but the result. Can the experts point out to me what I have done wrong? Thank you so much!
class Buyer {
static constraints = {
}
String buyerName
static hasMany = [purchases : GoodsPurchased]
}
class GoodsPurchased {
static constraints = {
delivery nullable:true
}
String goodsName
static belongsTo = [ buyer: Buyer, delivery : Delivery ]
}
class Delivery {
static constraints = {
}
Date deliveryDate
static belongsTo = [ buyer : Buyer ]
static hasMany = [ purchases : GoodsPurchased ]
}
A delivery can have one or multiple items that the buyer purchased; as not all the items are necessary for delivery. How do we define in the domain class that - a delivery can only contain items have have been purchased by the buyer before? How do we do that restriction in Grails?

If you want to achieve this in the Domain Class, you can check these business rules in the beforeInsert() and the beforeUpdate() that gets fired before the objects are inserted or updated in the domain class.
You can get more information about this here: http://gorm.grails.org/6.0.x/hibernate/manual/
However, the best place to implement these business logics are still in Services, or restrict the list in GSP for the users to select.
Hope this helps.

Related

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

Domain modeling using GORM in grails, how to represent an association

I am learning grails and I came up with a use case. In my use case, a product has many users and each user can have many roles.
Here is my product class:
class Product {
String name
String description
String vision
Date startDate
Date endDate
static hasMany = [users : User, contributors : User, watchers : User, approvers : User]
static belongsTo = User
static constraints = {
}
}
Here is my User class:
class User {
static constraints = {
}
String fullName
String email
static hasMany = [roles : Roles, products : Product]
}
Here is the Roles Enum:
public enum Roles {
PRODUCTOWNER ('ProductOwner'),
APPROVER ('Approver'),
CONTRIBUTOR ('Contributor'),
WATCHER ('Watcher')
}
My question is specifically about the association between Product and User. I want to represent the fact that a product can have many users in different roles. Also, each user can be part of multiple products with a different role in each product. Is this the right way to represent this relationship? Also, I should be able to remove and add users to products and vice versa. What this also means is that, users can keep moving between roles and can move in and out of products. In this scenario, I probably don't want cascades to happen. How do I prevent automatic cascades from happening to CRUD operations for this relationship?
Thanks.
I think rather than having roles and products in User.groovy, it will be better if you create a separate domain like UserProductRole. As you said user will have different role in different products then creating a separate domain makes more sense in business usecase and also doing queries
class UserProductRole{
Role role
static belongsTo = [user:User,product:Product]
static constraints = {
user (unique:['product','role']
}
}
You can create composite key but I generally dont perfer it because it makes querying bit difficult.
And now you need to change hasMany in User and Product like following
[userProducts:UserProductRole] rather then having users or products

Creating one-to-many & many-to-many for same domain class in grails

I want to create a domain class as like , One user can post many orders [Bidirectional] and one order can be liked by many users [unidirectional].
I have written a domain class as shown below ,
Class User {
String userName;
List orders
static hasMany = [Order]
}
Class Order {
String orderId
String orderName
//Indicates this order belongs to only one user
static belongsTo =[owner : User ] // Bidirectional
//Indicates order can be liked by many users
static hasMany = [likedUser : User] //Unidirectional
}
But I am getting am error saying invalid schema . Any body please help...
This post looks similar to my question but I am not getting , Please help.
First, order is a reserved word in SQL. Since GORM by default creates a table with the same name as your class, you'll need to either rename your class or provide a different name to use when mapping to SQL tables.
For example:
class Order {
static mapping = {
table 'user_order'
}
// ...
}
Another problem is that Order contains two associations to User. You need to tell GORM which one of these that is the bi-directional association from User to Order. That can be achieved using mappedBy, like this:
class User {
String userName
static hasMany = [orders: Order]
static mappedBy = [orders: 'owner']
}
Hope this helps.

Unidirectional Many To One mapping with cascade

Is it possible to map the following with GORM?
I want to get rid off all associated events when I delete a person.
Person object should not have a link to events.( I want to avoid using hasMany on Person domain)
class Person {
String username
}
class Event {
String description
static belongsTo = [person:Person]
}
I'm getting now a 'Referential integrity constraint violation' when doing person.delete() because events are not removed before deleting person.
I don't think that is possible without using hasMany (speaking of which, why do you want to avoid that anyway?)
This SO Question states:
Hibernate only cascades along the defined associations. If A knows
nothing about Bs, nothing you do with A will affect Bs.
Use static hasMany and bam, problem fixed.
Edit:
The only way I think you could achieve this is using beforeDelete on the Person class to delete all the associated Events, i.e.
class Person {
def beforeDelete() {
def events = Event.findAllByPerson(this)
for (e in events) {
e.delete()
}
}
}
See the documentation on Events and Auto Timestamping for more info on that.
The above will not work
Why not define a no reference mapping:
class Person {
String username
static hasMany=[Events]
}
This way there is no actual bindings of events to person but a person can have many events

Deleting m-to-m is also trying to cascade delete a one-2-one

I have the following Domains
class Committee {
String name
BoardCommitteeType boardCommitteeType
Date dateCreated
Date lastUpdated
User createdBy
User modifiedBy
static belongsTo = [
board: Board,
]
static hasMany = [
members: User
]
}
class User {
static hasMany = [
committees: Committee,
]
static belongsTo = [
Board, Committee
]
}
The problem is that when I attempt to do a board.removeFromCommittees(committee) I'm getting the following exception:
deleted object would be re-saved by cascade (remove deleted object from associations): [com.wbr.highbar.User#1];
I understand what that means. What I don't understand is why I am getting it. The other interesting bit is that if I make creatdBy and modifiedBy in the Committee instance null, the delete works just fine. That's why I am thinking that GORM is trying cascade the one-2-one. My theory is that is has something to do with the fact User belongsTo a Committee. But I don't know how to fix the problem.
The cascading delete is effected by the belongsTo relationships between your domain classes.
Since Committee belongsTo Board, when a Board gets deleted, the delete cascades to the Committee. Since User belongsTo Committee, when a Committee gets deleted, the delete cascades to the User.
The solution to your problem is to remove the User belongsTo Committee relationship.
Notes on your domain model as a whole:
You have a lot of many-to-many relationships. They're not necessarily wrong, but they might be overcomplicating things. You could probably get away with just using:
class Committee {
static hasMany = [boards: Board, users: User]
}
class Board {
static hasMany = [users: User]
static belongsTo = Committee // this is the only belongsTo you need, since if a
// committee is dissolved, presumably the board
// will be dissolved as well (unless you have
// cross-committee boards)
}
class User {
// doesn't define any relationships,
// let the Committee/Board domains handle everything
// also, this is presuming that users are at a higher level than committees, i.e.
// a user could belong to multiple committees
}

Resources