Return unique results when using findAllBy - grails

I have the following method in a service, please note the .user on the def usersByRole line:
def getUsersByRole(String desiredRole1, String desiredRole2, String desiredRole3) {
Role role1 = Role.findByAuthority(desiredRole1)
Role role2 = Role.findByAuthority(desiredRole2)
Role role3 = Role.findByAuthority(desiredRole3)
def usersByRole = UserRole.findAllByRoleInList([role1, role2, role3]).user
return usersByRole
}
It works good, but when a user has multiple roles (i.e. ROLE_ADMIN, and ROLE_OWNER) then that user exists twice in the collection if both of the previously mentioned roles are given as parameters. Is there any clean way I can make the collection contain only unique results?

A similar question as yours can be found here: GORM createCriteria and list do not return the same results : what can I do?
Method 1
If you want to return unique list of users directly from DB query then you can use listDistinct on User (supposing that user has a roles OneToMany association with UserRoles)
User.createCriteria().listDistinct {
roles {
in 'role', [role1, role2, role3]
}
}
Method 2
You can also try to query UserRole directly and group by User using the groupProperty (see http://www.grails.org/doc/latest/ref/Domain%20Classes/createCriteria.html)
Method 3
Remove duplicated users from the returned list:
UserRole.findAllByRoleInList([role1, role2, role3])*.user.unique()

The finder will return a List, and calling .user also returns a List, but you can cheat and cast it to a Set and it will remove duplicates. Since there's no order needed (you're returning def so it doesn't appear that you care about the collection type) you don't need to convert it back:
def getUsersByRole(String desiredRole1, String desiredRole2, String desiredRole3) {
Role role1 = Role.findByAuthority(desiredRole1)
Role role2 = Role.findByAuthority(desiredRole2)
Role role3 = Role.findByAuthority(desiredRole3)
return UserRole.findAllByRoleInList([role1, role2, role3]).user as Set
}
This presumes that you have a well-defined equals and hashCode in your User class so the uniqueness check makes sense.

Related

Rails distinct values of a value returned by a method in model

Suppose I have an Employee model, there is a method in Employee model named def fixed
def fixed
return self.cached_fixed.to_f if self.cached_fixed.present?
return (self.current_salary && self.current_salary.fixed).to_f
end
end
def current_salary
return #current_salary if #current_salary
# #current_salary = self.employee_salaries.detect{|es| es.end_date == nil}
#current_salary = self.db_current_salary
return #current_salary
end
if the fixed were a column in employee table we could have just used Employee.distinct.select(:fixed) to pull the distinct values
is there a way if it's just a method not a field in table without loading all the employees.
I am expecting to get the unique values of a column from a table , but it may not be a column as in the above table
Not for an arbitrary method, no. But you start the query from the EmployeeSalary end and fetch only the column you care about in one query using select:
EmployeeSalary
.select(:fixed)
.join(:employee)
.where(end_date: nil)
This will run a select fixed from... query and return a list of EmployeeSalary objects, but all the fields that aren't listed in the select call will be nil. Assuming the constraint of only one salary record having end_date: nil, there will be one EmployeeSalary object per employee. You can add .distinct in the method chain if you want unique values.
I'm not sure how the caching logic fits into this question. You can apply caching logic on top of that list if you like, but doing one query like this is pretty fast.

GORM using foreign key instead of domain object

Say I have a Domain Object User which contains an Organization field. I can map that using a foreign key and let hibernate take care of the rest like so:
class User {
String id
String firstName
Organization organization
static mapping = {
table 'user'
id column: "user_id", generator:'assigned'
organization column: 'organization_Id'
}
}
class Organization {
String id
String name
String address
static mapping = {
table 'organization'
id column: "organization_id", generator:'assigned'
}
}
This works fine, but when I want to query for all users in an organization I might have to do something like this
String orgId = "some id"
Organization org = Organization.findById(orgId)
List<User> users = User.findAllByOrganization(org)
It would be convenient to not have to pass the Organization domain object and instead just pass the Organization.Id which is the foreign key on the User table.
How I want my code to look is the following:
String orgId = "some id"
List<User> users = User.findAllByOrganization(orgId)
After researching, it seems like this is not possible, I need to first query for the Organization and then use that object. Is there a way I am unaware of?
One way I like to do it is to use a proxy of your domain object instead of a hydrated instance of it. You can use load() to obtain the proxy. This means no database call is made as long as you don't access any of the domain object's properties beyond the id.
def users = Users.findByOrganization(Organization.load(orgId))
You can use a Criteria:
String orgId = "some id"
List<User> users = User.createCriteria().list {
organization {
idEq(orgId)
}
}
You have two options there:
add a redundant orgId field to you User class and use it for the
lookup.
Use a fake object for your lookup:
.
Organization org = new Organization()
org.id = 'someId' // looks strange, but you can not use id inside constructor
def users = Users.findAllByOrganization org

How can I get grails to persist a list of objects in a class?

I have the following:
GroupMember.groovy
public class GroupMember{
String userName
String role
}
GroupProfile.groovy
public class GroupProfile{
List<GroupMember> groupMembers = new ArrayList<GroupMember>()
}
GroupProfileController.groovy
public class GroupProfileController{
def createProfile{
GroupMember groupOwner = new GroupMember()
groupOwner.userName = "testUser"
groupOwner.role = "OWNER"
groupOwner.save()
GroupProfile groupProfile = new GroupProfile()
def members = grouProfile.groupMembers
members.add(groupOwner)
groupProfile.save()
GroupProfile.list() //This list contains my GroupMember instance with the correct info
redirecT(action: myProfiles)
}
def myProfiles={
GroupProfile.list() //This list contains my groupProfile that I made but no GroupMember info
}
}
My GroupProfile won't save my GroupMember info. How can I get my GroupProfile to save the GroupMember info?
The normal way to represent this relationship in grails would be:
public class GroupProfile {
static hasMany = [groupMembers: GroupMember]
}
This will automatically generate a method on GroupProfile called addToGroupMembers that will create the associations. Saving the GroupProfile will also cascade to the group members, so you'll only need to call save once after adding the members.
Note that the groupMembers collection will actually be an instance of Set that doesn't necessarily preserve order. You can explicitly declare the collection as a List to preserve order, but it requires additional overhead including an extra database column, so make sure that's really what you want.
Check out the grails manual in the section on GORM: http://grails.org/doc/latest/guide/GORM.html

Filtering on multiple associations and optional where clauses

I've got a several domain classes, with some simple associations between them as follows:
class Business {
String name
City city
Industry industry
}
class City {
String name
}
class Industry {
String name
}
In my application, I would like to have a "filter" where the list of all businesses can be filtered according to the City and Industry. I am able to get the City and Industry id's from the filter back to the Business controller, however, when I get to the controller to do the filtering, I have this code:
...
def industry = Industry.get(params.int('industryid'))
def city = City.get(params.int('cityid'))
def businessList = Business.findAllByIndustryAndCity(industry, city)
...
This code works when both the City and Industry fields have values. However, sometimes the user might want to just filter by city or industry and not both. In this case, the filter fails, as when either of the values are null no results are returned. How could I specify that if either of the association values are "null", then the "find" query should remove this constraint altogether? i.e. match "all" for that field
Note that I realise that it would be easy to put an if statement checking whether the values are null and then executing a different "find" statement based on that. However, while this would work with two values, I don't think it would scale well as more filterable values are added.
You can build criteria.
def c = Business.createCriteria()
def results = c.list{
and {
if (industry) {
eq("industry", industry)
}
if (city) {
eq("city", city)
}
}
}
Check reference here in grails docs.
However your code needs N+1 queries for N parameters. Maybe you can reduce it to one query using criteria idea? If your Business entity holds foreign keys to both Industry and City this one should work:
def c = Business.createCriteria()
def results = c.list{
and {
if (params.industryid) {
eq("industry_id", params.industryId as Long)
}
if (params.cityid) {
eq("city_id", params.cityid as Long)
}
}
}
Both examples are untested but you should get the idea.

Help with Creating Models for Views

I am trying to create a Model to pass to a gsp view. I would like to do a sub query across two tables. I have two domains, alum_profile and alum_position. alum_profile has many alum_position's. alum_position belongs to alum_profile. In SQL if I wanted to create a result set, I would have something like this:
Select count(id),
(Select CONCAT(first_name, ' ', last_name)
From alum_profile
where
alum_profile_id =alum_profile.id ) as Person
FROM alum_position
GROUP BY alum_profile_id
ORDER BY count(id) DESC
How do I do this with HQL and create a model that can be passed to a gsp View.
Thanks for your help
jason
I am using Spring Source, with MySQL and writing in groovy on grails
From what I've read of your question, you want to display a list of the Profile's names, along with how many Positions each Profile has, sorted by the number of positions, desc.
First, you need Models:
class AlumProfile {
String first_name
String last_name
def hasMany = [positions: AlumPosition]
};
class AlumPosition {
String name // I just added this, no idea what you need in here
def belongsTo=AlumProfile
};
Now you want to create a list of the AlumProfiles sorted by position count. In your controller, you need:
def allByPositionCount = {
def profiles = AlumProfile.list().sort( [compare: { a,b -> a.positions.size().compareTo( b.positions.size() ) }] as Comparator );
[ profiles: profiles ]
}
This will render the allByPositionCount.gsp with the model containing the "profiles" member that is the list of profiles in the correct order, so something like:
<g:each in="${profiles}" var="profile" >
${profile.first_name} ${profile.last_name} has ${profiles.positions.size()} positions
</g:each>
should render what you want.

Resources