Need some explanation to understand how Grails works - grails

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

Related

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

Errors trying to search a many to many relationship in grails

I'm having trouble contructing a query within an many to many relationship... I have these domain classes:
class Event {
Appuser creator
static belongsTo = Appuser
static hasMany = [guests: Appuser]
and
class Appuser {
static hasMany = [friends: Appuser, events: Event]
So the idea is a user can have friends, and they can set up and own multiple events, and they can also be guests of other user's events.
My issue is constructing a query to get the list of guests for a particular event...
I've tried in my controller:
def guests = Appuser.findAllByEvent(eventInstance)
this gives an error
No property found for name [event] for class
def guests = Appuser.findAllByEvents(eventInstance)
this gives an error
No value specified for parameter 1
Any ideas how to remedy? Thanks.
Appuser.findAllByEvent doesn't make sense because there's no event property in the class. Dynamic finders can only work with persistent properties. findAllByEvents is more likely to work because there is an events property (added by an AST transform because of the hasMany) but you can't query on collections with dynamic finders; you need to use criteria/where/HQL queries for those.
But you don't need a query at all - just use the hasMany property you declared:
Event eventInstance = ...
def guests = eventInstance.guests

Modeling a many-to-one tree in grails

I'm attempting to model an organizational tree in grails. What I have works, but I have a couple of questions about it.
Here's my 'Organization' class:
class Organization {
String title
Organization parentOrg
static hasMany = [ childOrg: Organization ]
static mappedBy = [
childOrg: 'parentOrg',
parentOrg: 'childOrg'
]
static constraints = {
parentOrg nullable: true
}
}
Now, when I create a new 'Organization' like this:
def newOrg = new Organization(
title: 'New Organization',
parentOrg: oldOrg).save()
Everything works well, and the relationship to the parent seems modeled correctly.
But if I try to call something like oldOrg.childOrg.each I will get no results unless I have also called oldOrg.addToChildOrg(newOrg).
Furthermore, when I check the tables that are generated, the only reference to this relation is the parent_org_id column on the Organization table.
Now, I realize that this is all that is necessary to also determine the childOrg relations, but I don't notice ANY change in the database from before I call oldOrg.addToChildOrg(newOrg) to after!
So where is this relation getting stored when I call addToChildOrg when I don't see anything change in the database?
Also, how can I have this relation setup to automatically create the childOrg relation when I add the parentOrg? I don't think I should have to call addToChildOrg when I'm adding the parentOrg. It should be implied.
Thanks!
Use a hasOne association to store the foreign key reference in a bidirectional one-to-one.
Since you don't want to add the relationship from other side each time so you can make a setter to ease your work, like-
setParentOrg(parentInstance){
this.parentOrg = parentInstance
parentInstance.childOrg = this
}
Now when you do organisationInstance.parentOrg = parentInstance, the setter gets invoked for you, and the relationship is setup the way you want.
if I'm correct you're missing belongsTo definition, because you need to define that every instance of Organization is owned by its parentOrg instance.
try this class declaration:
class Organization {
String title
Organization parentOrg
static belongsTo = [parentOrg: Organization]
static hasMany = [ childOrg: Organization ]
static mappedBy = [ childOrg: 'parentOrg']
static constraints = {
parentOrg nullable: true
}
}

Creating one-to-many & many-to-many for same domain class in grails

I want to create a domain class as like , One user can post many orders [Bidirectional] and one order can be liked by many users [unidirectional].
I have written a domain class as shown below ,
Class User {
String userName;
List orders
static hasMany = [Order]
}
Class Order {
String orderId
String orderName
//Indicates this order belongs to only one user
static belongsTo =[owner : User ] // Bidirectional
//Indicates order can be liked by many users
static hasMany = [likedUser : User] //Unidirectional
}
But I am getting am error saying invalid schema . Any body please help...
This post looks similar to my question but I am not getting , Please help.
First, order is a reserved word in SQL. Since GORM by default creates a table with the same name as your class, you'll need to either rename your class or provide a different name to use when mapping to SQL tables.
For example:
class Order {
static mapping = {
table 'user_order'
}
// ...
}
Another problem is that Order contains two associations to User. You need to tell GORM which one of these that is the bi-directional association from User to Order. That can be achieved using mappedBy, like this:
class User {
String userName
static hasMany = [orders: Order]
static mappedBy = [orders: 'owner']
}
Hope this helps.

Sorting query results according to parent property in grails

Is it possible in grails to sort query results according to a property of a parent class in a relationship. E.g. I have a user domain class which has a one to many relationship with a list of Tasks.
When showing the list page of the Tasks domain class, I want to be able to sort the list of tasks by the associated User name.
class User {
String name
String login
String group
List tasks = new ArrayList()
static hasMany = [tasks:Task]
}
class Task {
String summary
String details
User user
static belongsTo = [user:User]
}
I can do something like this
Task.list([sort:"user", order:"asc"])
But this sorts by the user.id, is there a way to specify the sort to be on the user.name?
You can do it using Criteria
def criteria = Task.createCriteria()
def taskList = criteria.list {
createAlias("user","_user")
order( "_user.name")
}
iirc, grails sorts by using toString() and since you have not supplied one, it uses the id.

Resources