GORM how to model a relationship between like entities - grails

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
...

Related

Grails 3: find domains that were added to another one in many-to-many relationship (No value specified for parameter 1

I'm a Grails newbie and I found the following obstacle:
I have 2 domains: Course and Student, they have a many-to-many relationship (a Course can have several students, a student can enroll in several courses) and the student belongs to the course.
So, when I add a student to a course, I want to be able to find what Courses have added a specific student.
I tried to use:
def s = Student.get(id)
def c = Course.findAllByStudents(s)
But grails keeps telling me "No value specified for parameter 1".
Can you guys throw some light into this?
Course.findAllByStudents expects as parameter Set of Students but you are supplying it with single instance of Student, that's why you are getting "No value specified for parameter 1".
To find in what Courses is Student. If you created domain classes like this:
class Course {
//some Course attributes
static hasMany = [students: Student]
}
class Student {
//some Student attributes
static hasMany = [courses: Course]
static belongsTo = Course
}
then you can simply use s.courses.
If you are not two-way mapping that relationship. You can create criteria like this:
Course.withCriteria {
createAlias 'students', 's'
eq 's.elements', s
}

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

Grails belongsTo multiple classes

I have a domain class that can belong to one of several classes. I'm seeing validation errors when I try to save.
class Teacher {
Book book
}
class Student {
Book book
}
// book can belong to either a student or a teacher
class Book {
static belongsTo = [student : Student, teacher : Teacher]
}
The validation error suggests that a book must belong to BOTH a student and a teacher (neither can be null), but I want to model it so that it can belong to either. How do I do this please?
Please disregard the fact that for my example you could change it so that a Person owns a book and a Teacher and a Student are both types of Person - I want to know how how to create the correct belongsTo.
Edit to explain reasoning behind requirement:
There will be 3 tables created: Book, Student and Teacher. I need to be able to create an index on the Book class that refers to Student and Teacher. This is so the query that is "find all books that belong to Teacher A" can be made as fast as possible.
If there was just a single belongsTo (example shown if for owner teacher)then this is done like this:
static mapping = {
teacher index: 'teacher_idx'
}
Well this is very much doable, its just that your approach is wrong here.
belongsTo is used in a way when an entity must and must be mapped with some other entity. There is nothing like either of them.
What you can do is
1. create an Abstract Domain `Book`
2. create an Domain `StudentBook` it belongs to `Student`
3. create an Domain `TeacherBook` it belongs to `Teacher`
So here only one table will be created for the three Domains, named as Book. This table will contain a field class which will determine if the book belongs to Student or Teacher.
If I understand you then you can use other version of belongsTo which does not store back reference of Owner Class e.g
class Book {
static belongsTo = [Student, Teacher]
}
Ref

Domain design to store user's country, age group, etc

Here is the situation: a user table contains data that overlap with other users' data such as country, age group, gender, etc.
In MySQL, I would use three tables or two. In the case storing country, I would use three tables: one would the be user table, the other country table, and the last one that joins the two. (Of course I could use two tables if one user has one country.)
ex) user(id, otherUserInfo),
userCountry(id_user, id_country),
country(id, countryName)
Being new to Grails, I was wondering what's the best way to represent this schema. Is it necessary to create 2-3 domain classes? Or is there some magical feature (like so many other Grails features (: ) to do this in a single domain class.
More than likely you could do it with two.
class User {
//other user info
//if user only has one country
Country country
//if user has many countries
static hasMany = [countries: Country]
}
class Country {
//country info
}
Since you probably don't want a Country to belong to the User, you don't need anything in the Country class to indicate ties back to the User. Grails/Gorm will handle creating the linking entities in either of these cases.
If the user has many countries and you needed to store other information regarding the relationship you would need to create your own join table. For example if you needed to keep the number of visits the user has made to the country:
class User {
//other user info
static hasMany = [userCountries: UserCountry]
}
class UserCountry {
static belongsTo = [user: User]
Country country
int numberOfVisits
}
class Country {
//country info
}

How to define association relationship in grails

UPDATED
I have a domain classes as below
class Training{
// has one createdBy object references User domain and
// has one course object references Course domain
// has One Trainer1 and Trainer2 objects refernces Trainer Object.
}
class Trainer{
String name
//can have many trainings.
//If Trainer gets deleted, the trainings of him must be deleted
}
Class User{
String name
// can have many trainings.
}
class Course{
String name
//If Course gets deleted, Trainings of this course must be deleted
// can have many trainings.
}
I have got a training create page, Where I have to populate already saved Course, User, Trainer1 and Trainer2. I am not saving them while Creating the training.
So, How to specify the relationship in grails
You did not put any effort to searching answer for yourslef. There are plenty basic examples and blog posts how to map relations in Grails. You should start with Grails documentation of GORM - Grails' object relational mapping. You can find it here.
I see some minor flaws in yout initial design: ie why should training be deleted if user is deleted when trainings will obviously tie with many users. Can training exists without trainers or vice versa ?
I would start with something like this:
Class Training {
static hasMany = [users: User, trainers: Trainer]
static belongsTo = Course
}
Class Trainer {
String name
}
Class User {
String name
}
Class Course {
String name
static hasMany = [trainings: Training]
}
EDIT: I have to agree with Tomasz, you have jumped here too early without searching for answers yourself. Grails.org has good documentation about GORM with examples too.

Resources