Two way one to many relationship - grails

I have two domain classes one is Game:
class Game {
String name
String description
Double price
static hasMany = [reviews: Review]
}
and the other one is Review:
class Review {
String reviewText
Date reviewDate
static belongsTo = [game: Game]
}
Both are stripped down versions. I have two objects
r1 = new Review([reviewText: "A game review", reviewDate: new Date()])
g = new Game([name:"Angry Birds", description:"Parabolic physics like game", 20.00])
r1.game=g
r1.save()
After above call is this statement legal?
g.reviews
Will it return a list of all reviews associated with Game? Actually I have an old Grails code which is fetching list of reviews by g.reviews like calls and on Grails 2.4.4, I am getting a null. Was it legal in older versions of Grails? What is the recommended way to fetch reviews associated with a particular game?

save with flush:true if you want to immediately access the db.
r1.save(flush:true)
then you can say:
g.reviews

Related

Grails domain associations with cascading save enabled and transactions

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.

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 accessing relationship tables

I have one many-to-many relationship in my app which looks like this: class
App {
String type
String name
static hasMany = [users: User]
}
class User {
String email
String regid
static belongsTo = App
static hasMany = [apps:App]
}
Now i want to access all Users of an app, by having its id. I prefer using plain SQL as It is working way faster and I database will have ~one million records. So i need a way to access all users of an app where app id in (array of given apps).
What I am trying is doing something like this:
def result = sql.eachRow('SELECT App_Users from App where id in(?)' [id:params.app_checkbox])
But this throws me exception as column App_users is not available.
I am trying to do this for 4-5 hours and bearing in mind I am not a web developer, it is already driving me crazy, so could you guys give me advice, how to access members of many-to-many relationship with sql?
At last i managed to achieve it with simple criteria:
def results = App.createCriteria().list() {
createAlias('users', 'user')
'in'("id", goodIds)
projections {
count('users')
}
}

Grails not setting database up as expected

Hi this have been going on for several months now and I have lost all hope.
I have 3 domains in question.
Product which is made up of Components, each Component can have alternative products.
Here are my models:
Product:
class Product {
String name
String comments
static hasMany = [components:Components]
}
Component:
class Components {
Product product
static hasMany = [alternatives:Alternatives]
}
Alternatives:
class Alternatives {
Product product
}
To populate this I am parsing an excel Spreadsheet here is the code that does it:
Product st = new Product(
name: row.getCell(0).getStringCellValue().toUpperCase(),
comments: "test"
)
row.getCell(10).getStringCellValue().split("[|]").each {
Product pro = Product.findByName(it.toUpperCase())
if(pro) {
Components c = new Components(product: pro).save(flush:true)
s.add(c)
// Does not work
//st.addToComponents(c)
}
}
st.save(flush:true,failOnError:true)
This does not create a table in the database called product_components. this is what I would expect.
When I try and use addTo the component has a product instance associated with it, the product instance is then changed to the st product instance which I am trying to save it to.
I hope that makes sense.
I have found out that it is mapping the product in the Components domain as the component in the Product domain.
I am now assuming that using mapped by in the Product table may fix it
static MappedBy = [components : //do something here ]
Found the answer see bellow:
I had to add the following in my Product domain.
static mappedBy = {components joinTable: [name:'product_components',
column:'COMPONENTS_ID',
key: 'PRODUCT_ID']}
and change the name of product to part_of in my Components domain.
The way you have it set up now, your Components class only allows one product. So you have a one-to-many relationship from Product to Components, this is the reason the join table product_components is not being created.
You are also trying to assign a Components instance to multiple products:
// To the 'pro' Product
new Components(product: pro)
// To the 'st' Product
st.addToComponents(c)
But your Components domain class only allows for one Product, which is why the referenced Product is being overwritten.
If you want your Components class to have more than one product (which is what the code you've written is trying to accomplish), you'll have to add the Product class to your static hasMany block on Components:
class Components {
static hasMany = [alternatives: Alternatives, products: Product]
}
Then you can perform the following:
def c = new Components().save(flush: true)
pro.addToComponents(c)
st.addToComponents(c)
On an unrelated note, I would recommend making your domain class names singular, i.e. Alternative and Component to follow Grails' conventions and to make more sense.

Grails domain class design for ERP requirement

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.

Resources