How to create multiple one-to-many relationships between domain classes - grails

I have an Account class that has many managers (User class) & reps (User class).
class Account {
static hasMany = { reps: User, managers: User }
}
Then, I have a User class which belongs to an account. User is differentiated into manager or rep using a Role Enum inside User class.
class User {
static belongsTo = { account: Account }
Role role
}
The problem is, when I create a user of any type and save it, Grails ends up adding that user to both managers and reps sets in the account object.
I realize I need to use mapped_by here, however I don't understand how it should be used. The manager and rep is differentiated by a Role Enum inside User class.
I have looked at several stackoverflow questions #1, #2 however most of the times, problems get solved with other relationships.
I specifically want to use 2 one-to-many relationships between the Account and User class.
Edit : Code to initialize a rep:
def addRep(manager) {
User rep = new User( account: manager.account,
role: Role.REP)
rep.save(flush: true, failOnError: true)
}

You need to specify which association is to be used :
def addRep(manager) {
User rep = new User(role: Role.REP)
manager.account.addToReps(rep) // This will do the bi-association
rep.save(flush: true, failOnError: true)
}

Related

GORM how to model a relationship between like entities

I'm making an e-learing platform in Grails and I'm not sure how to go about modelling the domain classes. I have the following classes: User, Role (student, instructor, admin...), UserRole and Course.
I want to make it so that every Course belongs to one instructor(User), and every Instructor can have many Courses. But also every student(also User) can be enrolled in many courses. My problem is that instructor and student are both one class (User).
I tried to make it like this by making an additional class Enrolment which keeps record of every student enrolled in each class, but I'm not sure it's ok.
class User {
String username
String password
...
class Course {
String title
String description
static belongsTo = [ instructor : User ]
...
class Enrolment {
User student
Course course
...

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

How to track changes to a GORM-managed collection?

Imagine the following domain classes:
class User {
static hasMany = [ roles: Role ]
List<Role> roles
User() {
roles = new ObservableList<>()
roles.addPropertyChangeListener({ event -> ... } as PropertyChangeListener)
}
}
class Role {
String name
}
My intention is to perform some actions each time an element is added to / removed from the roles collection; this includes 1) populating roles from database, and 2) further manipulation by a user. If a User instance is just created (and not persisted), I am able to catch notifications. After the call to save() method, the ObservableList is still intact. But later, for example, when I perform a User.find...() from a controller, the original ObservableList is replaced by Hibernate's org.hibernate.collection.PersistentList, and obviously there are no notifications anymore.
How can I implement a change-aware list that would be compatible with GORM?

Need some explanation to understand how Grails works

I'm new to Grails, some things are still vague for me.
I want to create a Twitter-like app. As a user has both a followers and a following groups, I've created a GroupMyTwitter domain.
What I don't understand, is the logic behind this. My GroupMyTwitter domain is like this :
class GroupMyTwitter
{
String name;
static constraints = { name blank : false; }
static hasMany = [users:UserMyTwitter];
static belongsTo = [owner:UserMyTwitter];
}
Then every time I create a user I also create two groups associated to him :
GroupMyTwitter followers = new GroupMyTwitter (
name:"followers",
owner: user).save(flush: true, failOnError: true)
// And same for followings
Now I simply wonder... how can I access these groups to get the followers/ings count, add or delete some?
Thanks for your help.
Based on the hasMany and belongsTo variables gorm automatically creates some instance fields for you:
static hasMany = [users:UserMyTwitter];
This will create a field users of type Set inside GroupMyTwitter.
You can access this Set like any other field:
followers.users.add(userA) // add a user
followers.users.remove(userB) // remove a user
followers.users.size() // number of users
// don't forget to save the group after you modfied the `users` collection:
followers.save(failOnError: true)
Depending on your needs it might be useful to use a List instead of a Set:
class GroupMyTwitter {
List users
static hasMany = [users:UserMyTwitter];
...
}
This causes Gorm to use a List for the users collection instead of a Set.
A List has a defined order and allows you to access certain elements by index:
UserMyTwitter user = followers.users[4] // get the 5th user

Mixed relationship in grails application

I have a domain class which is called Event. Event has many registrations, which are users with account on site or people without it. I want registered user to be able to track their events, so Event-User relationship should be bidirectional (user is created by Spring Security). Still there are registrations which are not connected with user accounts. It's important since event is kind of a live competition with ranking, which is updated by event owner when event is over. How to achieve this?
this should work:
class User {
static hasMany = [events:Event]
}
class Event {
User user
static constraints = {
user(nullable:true)
}
}
this way you can get the user from the event or all events for the user.
EDIT:
class User {
static hasMany = [events:Event]
}
class Event {
static hasMany = [users:User]
}
add Users to the Event with
event.addToUsers(user)
remove Users from Event with
event.removeFromUsers(user)
get all Users from Event
event.users
I'm not quite sure how you handle the not registered Users. Do you have no information about this users at all (no username etc ?)
I would suggest you add a flag in the User class "Boolean registered".
So you can create a User object for not registered Users also.
cheers manu

Resources