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.
Related
Say we have the following two domain classes:
class Book {
static belongsTo = [author: Author]
}
class Author {
static hasMany = [books: Book]
}
No if an Author is initialized with several books and Author.save() is called then the save cascades to Book and both Author and Book instances are saved into db.
However I can't find anywhere in documentation if the mentioned operation will be done transactionally or not.
Any idea?
Any resource to check ?
The answer depends on where the save is done. Is it done in a controller action marked as transactional? Is it in a service which uses transactions by default? Or is it done somewhere else where there is no transaction.
If the save is done somewhere that supports transaction (two examples above) then yes, it will be. Otherwise, no it won't be.
Say we have something like the standard Book domain object and bookCategory object. In my controller I want to return a subset of list of books to the view. That subset is not achievable using a find query. When I try to filer the return object, it deletes relationships from the database!
I tried this:
class BookCategory{
String name
static hasMany = [books:Book]
}
class Book{
String title
}
def myController() {
def categories
categories = BookCategory.list()
def user = getCurrentUser()
categories.each { category ->
category.books.removeAll { book ->
!isBookBannedForThisUser(book.title, user)
}
[bookCategories: categories]
}
}
The problem is that it permanently removes these books from the categories for all users from the database!!!
I tried putting the method in a service and using a readonly transaction, but this did not help.
I assume that even if I copy all the categories and books into new list, they will still update the DB as they will still have the book IDs (which I need)
Saving to the database when you dont say save() is very dangerous. is there a way to disable this feature completely?
There is a fundamental flaw in your approach. Do not modify your domain instances if you don't intend to have the changes persisted. Doing so is going to cause you headaches.
Your domain model is suppose to be your system of record. Any changes to it are suppose to be persisted.
If you need to gather up data and manipulate it without having it reflected in your domain model then use a DTO (data transfer object) or similar pattern.
Simply calling .discard() will discard the changes you have made from being persisted when the session automatically flushes.
Instead of working against the framework, and disabling behavior, change your approach to be correct.
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
I am a beginner in GRAILS so i am hoping some help on the issue i am facing.
I have read the documentation but i am still vague on the idea of relationships in grails. In grails, you could have 4 types of relationship between domain classes.
1 to 1
1 to many
many to 1
many to many
Grails has three constructs to define relationships
static hasMany =
static belongsTo =
static hasOne =
My question and dilemma is why do we need these three constructs to define a relation when we could just specify what type of objects each class has that would automatically define relationship between domain classes.
for example
To define many to many i could have two classes designed this way
class Author{
Set<Book> books
}
class Book{
Set<Author> authors
}
For 1 to many and many to 1
class Author{
Set<Book> books
}
class Book{
String title
}
for one to one
class Author{
Book book
}
class Book{
Author author
}
I appreciate it if anyone can give me a clear, easy to understand explanation. Thank you!
Everything you defined there should work fine. You don't have to use any of the other stuff that you mentioned that GORM offers, but there are reasons that you might want to. For example, you can write a class like this:
class Author{
Set<Book> books
}
That is not the same thing as this:
class Author {
static hasMany = [books: Book]
}
When you use hasMany, Grails generates this for you...
class Author {
Set<Book> books
def addToBooks(Book b) {
books.add(b)
this
}
def addToBooks(Map m) {
books.add(new Book(m))
this
}
def removeFromBooks(Book b) {
books.remove(b)
this
}
}
That isn't exactly what is generated, but that is some of the stuff that you might care about.
There is more to it than is represented there. For example, if the Book has a reference back to the Author, the addToBooks methods will hook that back reference up for you.
There are other behaviors associated with the other properties you mentioned. For example, the hasOne property switches the direction in which the foreign key points on the persistence model. The belongsTo property enforces cascading of certain events. etc.
Take a look at the GORM docs at http://grails.org/doc/latest/guide/GORM.html for more information.
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