Multi joins in context of BelongsTo - laravel-nova

In the context of Laravel Nova. I have the following tables in a database:
order:
id
group_id (references group.id)
group:
id
user_id (references user.id)
user:
id
member_id (integer)
In my index view of order I can easily display a column with user_id using this in my Order Resource:
BelongsTo::make('User ID','Group', 'App\Nova\Group')->display('user_id'),
But how do I display member_id? Pseudo wise:
BelongsTo::make('User ID','Group', 'App\Nova\Group')->display('user_id') --> BelongsTo::make('Member ID','User', 'App\Nova\User')->display('member_id') ?
Any help appreciated - Thanks!

Write a specific method in the model and use it:
/**
* Get the user that owns the phone.
*/
public function userId()
{
return $this->belongsTo('App\User', 'foreign_key', 'other_key');
}
And in the resource field, specify this method:
BelongsTo::make('Member ID','userId', 'App\User')

Related

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

ID lookup field in GORM in grails

I am new to Grails and GORM and I am trying to One to Many relationship but not with default id field. Here is my scenario:
Table structure in the database:
USERPROFILE
iduserprofile
username
ROLE
idrole
rolename
USER_ROLE
iduserprofile
idrole
Domains:
class Userprofile {
long iduserprofile
String username
static mapping = {
datasource 'ALL'
id name: 'iduserprofile'
version false
}
class Role {
long idrole;
String rolename;
static mapping = {
datasource 'ALL'
id name: 'idrole'
version false
}
}
class UserRole {
Userprofile user
Role role
static mapping = {
datasource 'ALL'
version false
}
}
When I try to get the user or role object from UserRole domain, it is always looking for user_id or role_id in the USER_ROLE table.
Why is it not looking for iduserprofile or idrole? How can i change the code to look for isuserprofile or idrole?
Thanks
GORM by convention will use/generate id as identifier for your domains. If you have legacy tables or just a desire to break convention, you'll need to specify your custom column names. For example for Role mapping, add the following:
static mapping = {
datasource 'ALL'
id name: 'idrole', column: 'idrole'
version false
}
It seems to me that the easiest thing to do would be to copy your database and then change the names of the id fields if you have legacy tables. If not then just make life simple by conforming to convention.

Select of hasMany mapping with GORM in Grails

Suppose I have a setup like the following:
class User {
static hasMany = [items : Item];
}
class Item {
String name;
}
I'm trying to select all Users that have an Item in that hasMany mapping. I have an id of an Item, and want to find all users that “have” that item.
Is there a HQL query I can run that will do this or better yet, a built in GORM function that handles this query?
Supposing this were straight SQL I would do something like:
SELECT `user_id` FROM `user_item` WHERE `item_id`=[ID]
Looking in H2 I can write the query
SELECT USER_ID FROM USER_ITEM WHERE ITEM_ID=1;
I can expand this SQL to include the entire user object:
SELECT * FROM user, user_item WHERE user_item.item_id=[item id] AND user.id = user_user.user_items_id;
This HQL will work:
Item item = ...
Item.executeQuery(
'from User u where :item in elements(u.items)',
[item: item])

Return unique results when using findAllBy

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.

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