How to use createCriteria for many-to-many relation in Grails? - grails

I have domain classes as below:
class Account {
String name
String uniqueName
static hasMany = [roles:Role]
}
class Role {
String name
static belongsTo = [account:Account]
static hasMany = [users: User]
}
class User {
String name
}
I received Account's uniqueName from params.uniqueName. And I want to find all users list that has roles that belongsTo account.
I want to use criteria() because I want to do it in pagination.
I try like below code, it's work but it can't do a pagination.
def account = Account.findByUniqueName(params.uniqueName)
def roles = account.roles
[users : roles.users.flatten().unique()]
How should I do this?

Try this one:
add to user:
static belongsTo = [role:Role]
and use this criteria:
User.createCriteria().listDistinct {
role{
account{
eq("uniqueName", params.uniqueName)
}
}
}

You can use criteria like this.
List<Account> results =Account.createCriteria().list
{
eq('uniqueName', params.uniqueName)
maxResults(params.max as int)
firstResult(params.offset as int)
order(params.order, "asc")
}

Try this:
Account account = Account.findByUniqueName(params.uniqueName)
Collection users = []
account.roles.each{ role ->
users += role.users
}
log.info("Users for ${params.uniqueName} account : ${users}"

Related

Grails - findAll joining two tables

I'm new to Grails. I'm having problem with retrieving data from DB. I have domains with classes, something like...
class Lightbox {
String name = ''
String link = ''
static hasMany = [users: LightboxUserAccount]
}
class LightboxUserAccount {
UserAccount userAccount
static belongsTo = [lightbox: Lightbox]
}
class UserAccount {
String username
...
}
I want to list all "Lightboxes" owned by user with ID=4. I was trying
def my_lb = Lightbox.findAll("from Lightbox as lb where lb.users=:userAccount", [userAccount: springSecurityService.getCurrentUser()])
or
def my_lb = Lightbox.findAllByUsers(4)
None of those work for me. What am I doing wrong? Thx
Try this one:
Lightbox.findAll("from Lightbox as lb where :userAccount in (lb.users)", [userAccount: springSecurityService.getCurrentUser()])
So I did it slightly different, using criteria instead. Take a look if interested
static getAllByUserAccount(UserAccount userAccount) {
def criteria = Lightbox.createCriteria()
def my_lb = criteria.list {
users {
eq('userAccount', userAccount)
}
}
return my_lb
}
It seems to be working. Thanks for responses though

Grails : get a list of elements with a belongsTo relationship?

Assuming I have a Person and a Status. If Status is like this :
class Status {
String text
Person author
}
I would have done something like this to get the messages list of the current user :
def messages = Status.withCriteria {
author {
eq 'username', currentPerson.username
}
}
But if my relationship in Status is like this, how can I do so?
static belongsTo = [Person]
Thanks for your help.
I tend to use the map notation for belongsTo, so I would do it like this:
class Status {
String text
static belongsTo = [author: Person]
}
Then you're query is easy:
def messages = Status.findAllByAuthor(currentPerson)
If you had bidirectional added into Person with hasMany:
class Person {
static hasMany = [messages: Status]
}
You could also do this:
def messages = currentPerson.messages

Grails one-to-many / wrongly deleting all "manys"

i have the following (simplified) domain classes
class Filter {
String name
static hasMany = [answers:Answer]
static belongsTo = [user:User]
}
class User {
String name
static hasMany = [answers:Answer, filters:Filter]
}
class Answer {
String text
}
Then i add answers to the user which is working perfectly. The problem occurs when i delete 1 answer of a user:
def delete = {
def answer = Answer.get(params.id)
def users = User.withCriteria() {
answers{
eq("id", answer.id)
}
}
for (user in users)
user.removeFromAnswers(answer)
answer.delete(flush:true)
redirect(action:"index")
}
What happens here is that ALL user --> answer associations get deleted.
I only want to delete this 1 answer and of cause all associations the answer is used.
I know this has to do with the missing belongsTo, but i can't use it because a ansswer can either belong to a user or to an filter...
You can add the belongsTo to set them to nullable:
class Answer {
String text
static belongsTo = [user:User, filter:Filter]
static constraints = {
user nullable:true
filter nullable:true
}
}
and then just delete the Answer directly in the Controller:
def delete = {
def answer = Answer.get(params.id)
answer.delete(flush:true)
}
GORM will take care of the rest the cascading for you.

Issue with many-to-many and mapping

This is my first project with many-to-many relationship and after reading some grails stuff of ORM, I decided to let grails do the work for me, like creating the tables. Actually, my deal was:
1 User has many Groups
1 Group belongs to an User and has many Users(except the owner)
Here are my classes:
class User {
String name
List groups
static hasMany = [groups : Group]
static mapping = {
table 'users'
version false
}
}
class Group {
String name
List members
static belongsTo = User
static hasMany = [members : User]
static mapping = {
table 'groups'
version false
}
}
After that, what I got from grails was 3 tables. The users table was ok, but the next 2 wasn't what I expected.
table **groups** | id | name
table **users_groups** | group_id | user_id | members_idx | groups_idx
Well, what I wanted was something like this:
table **groups** | id | name | user_id
table **users_groups** | group_id | members_idx | groups_idx
I don't know if I did something wrong or how can I fix it, but anyway... I'm still getting another problem when I try to do user.addToGroups(new Group()) . My users_groups table duplicates this register, one with the members_idx null, and the other register with the groups_idx null.
How about removing belongsTo from group and leave hasMany:
class User {
String name
List groups
static hasMany = [groups : Group]
static mapping = {
table 'users'
version false
}
}
class Group {
String name
List members
static hasMany = [members : User]
static mapping = {
table 'groups'
version false
}
}
EDIT
I think You have to make a domain class which will actually join groups and users.
I think You should try this:
class User {
String name
static hasMany = [groups : UsersGroups]
static mapping = {
table 'users'
version false
}
}
class Group {
String name
static hasMany = [members : UsersGroups]
static mapping = {
table 'groups'
version false
}
}
class UsersGroups {
static belongsTo = [group: Group, user: User]
static mapping = {
version false
}
}
It will create another table which actually joins groups and users.
If you change the belongsTo to use Map syntax it will use a foreign key and not a join table:
static belongsTo = [user: User]
and you'll have a user field as a back-reference.
I have done a similar issue before, so I think this may work:
class User {
String name
hasMany = [groups : Group]
static mapping = {
table 'users'
version false
}
}
class Group {
String name
static belongsTo = [owner : User]
static hasMany = [members : User]
static mapping = {
table 'groups'
version false
}
}
About the problem with user.addToGroups, I think that you should set the owner when creating the group first. Then add other users to group.

sorting problem with multiple joins

I have a problem getting sorting to work with multiple joined tables. For example:
class Account {
static hasMany = [subscriptions: Subscription]
static mapping = {
subscriptions fetch: 'join'
subscriptions sort: 'magazine'
}
}
class Subscription {
static belongsTo = [account:Account, magazine: Magazine]
static maping = {
magazine fetch: 'join'
magazine sort: 'name'
}
}
class Magazine {
String name
static mapping = {
sort name: 'desc'
}
}
When someAccount.subscriptions is called generated query orders by magazine.id. Is there any way to get order by magazine.name? I tried changing to subscriptions sort: 'magazine.name' but get an error there is no such property.
Following: http://grails.org/doc/latest/guide/single.html#5.5.3 Default Sort Order I tried to move sort to association level by removing sort from Account and keeping sort in Subscription only but that ended up removing "order by" from resulting query completely. Any ideas? Thanks.
Try implementing a compareTo method in your Magazine class:
class Magazine implements Comparable {
String name
int compareTo(obj) {
name.compareTo(obj.name)
}
}
Then one in Subscription
class Subscription implements Comparable {
static belongsTo = [account:Account, magazine:Magazine]
static constraints = {
}
int compareTo(obj) {
return magazine.compareTo(obj.magazine)
}
}
Then make the subscriptions a SortedSet in Account:
class Account {
SortedSet subscriptions
static hasMany = [subscriptions:Subscription]
}

Resources