I have an Author who has many books. A book has many chapters. The book is published by different publishers who pay different commissions.
So, the domains will be.
Author { hasMany [books: Book] }
Book { hasMany [chapters: Chapter, publishers: Publisher] }
Publisher { }
Grails generates the book_chapter and book_publisher tables. So far so good.
The database looks good.
Commission is a value of the type Single. But where do I put the commission?
Would you show me how to set this up please?
Many Thanks!
I give up. I don't know how to set up the relationship between the Author, Book, and Publisher. The idea is simple. Different publishers will pay me different commissions for my books.
I will remove the hasMany Publisher relationship from the Book. So, my Book is just now:
Author { hasMany [books: Book] }
Book { hasMany [chapters: Chapter] }
Publisher { ... }
Now I will add a Commission domain to have my commission amount stored in the database.
Commission {
Author author
Book book
Publisher publisher
Float amount
}
Next I need to make a composite primary key with both Author, Book, and Publisher. This will prevent duplicated records. It is because this is not correct to have more than one record in the database to show how much the publisher pays me for the same book.
I think this will work. What I need to do next is to program the controller to fill out the commission objects manually.
I originally don't want to think or type too much if I can use the built-in scaffolding. Let Grails do all the heavy lifting for me. I don't think I can use the scaffolding anymore.
Good job me.
Please leave a comment.
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.
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.
I am having to two domain classes Order and Stock. When stock is sold I am creating an entry in the child table StockOrder which contains information about the Order(order_id) and Stock(stock_id) and noOfStockSold.
In my current design I coded the StockOrder close to Stock table. You can see this below.
Class Stock {
String stockName
BigDecimal quantity
List stockOrderList
static hasMany = [stockOrderList: StockOrder]
}
class StockOrder {
Stock stock
Order order
BigDecimal noOfStockSold
static belongsTo = [Stock]
}
class Order {
List saleLineItemList
static hasMany = [saleLineItemList: SaleLineitem]
}
Am I doing to correctly from ERP prespective. How to relate Order to Stock sold?
Is it ok if I tie StockOrder to Order also by doing static belongsTo = [Stock,Order]
Is there any better way of doing it or any improvements?
I would start by reading these:
http://grails.org/doc/2.0.x/ref/Domain%20Classes/belongsTo.html
http://grails.org/doc/2.0.x/ref/Domain%20Classes/hasMany.html
Basically you use the belongsTo and hasMany to describe bi-directional relationships. This allows you to cascade delete objects if you so desire. I would imagine in an ERP system that you wouldn't want cascading functionality because if you delete a Stock you probably don't want to delete all the associated StockOrder. I would probably keep the hasMany side of the relationship and remove the belongsTo since you're already associating a StockOrder to a Stock and an Order.
Consider the following domain classes
class Business{
static hasMany = [contacts:ContactPerson]
}
class ContactPerson{
}
Given the following domain classes, say we use the following examples:
Alice is ACME's contact person. Bob and Carol are Calamity Corp's contact person.
Say I wanted to remove Bob in the ContactPerson table. Thus:
bob.delete(flush:true)
But the code will result to the server complaining about contraints:
ERROR: update or delete on table "contact_person" violates foreign key constraint
"fk4a69c6b329ef2fe1" on table "business_contact_person"
Detail: Key (id)=(174) is still referenced from table "business_contact_person".
In this context, the exception is thrown because Bob is still associated with Calamity Corp.
How do I delete Bob from the ContactPerson table? I wanted to remove Bob from the database altogether. I don't want to add belongsTo since I don't want to cascade the delete to Business' children (that is to say, if I delete Acme Corp from the database, I still want Alice to be in the system).
I've seen examples on disassociating the parent from the child but not the other way around.
I believe by simply adding a belongsTo, the cascade should work as expected...
class Business{
static hasMany = [ contacts:ContactPerson ]
}
class ContactPerson{
static belongsTo = [ business: Business ]
}
Ok. So with a little more digging, I finally got the codes that I wanted. John Rellis' post on Relationship Advice : Grails One-To-Many was especially helpful. In this article, he mentions how to query from children to parent (which is exactly what I am looking for).
Going back to the question, I wanted to remove Bob from the ContactPerson table but given the relationship between Business and ContactPerson simply calling bob.delete() simply would not do. What I need is to look for all businesses associated with Bob and remove the association. Thus the code below:
def bob = ContactPerson.get(params.id)
def criteria = Business.createCriteria()
def businesses = criteria.listDistinct{
createAlias("contactPersons","c")
eq("c.id", bob.id)
}
businesses.each{business->
business.removeFromContactPersons(bob)
business.save(flush:true)
}
bob.delete(flush:true)
I also added a new mapping to the Business domain model:
static mapping = {
children cascade:"all-delete-orphan"
}