How to create a Query for users based on role

Topics: Customizing Orchard, Writing modules
Jan 19, 2013 at 8:48 PM

I am trying to create a Projection of all my users with a particular role.

When creating the Query for the Projection, I see where I can use UserName and Email from the User Part Record, but no role.

How would I go about creating a Query that filters on users' roles? Is a Projection even the way to go?


Jan 19, 2013 at 9:45 PM

The role is in a different part: UserRolesPart.

Jan 19, 2013 at 10:15 PM

Thanks Bertrand.

I do not see that part amongst the available Parts when I create a filter for a query. What must I do to enable this for queries?

Jan 19, 2013 at 10:16 PM

You may have to build your own filter.

Jan 19, 2013 at 10:25 PM

Ah.  I see.

That fills me with no small amount of trepidation.

How do I build my own filter? Is there a tutorial or guide somewhere? Or, maybe you can direct me to where I can find the code for an existing query.


Jan 19, 2013 at 10:40 PM

The Projections module itself contains a few filters, as well as Contrib.Taxonomies (look in the Projections folder and for IFilterProvider implementations).

Jan 19, 2013 at 10:42 PM

Jan 20, 2013 at 2:43 AM


I'll take a look at all of that and let you know how I fared.


Feb 24, 2013 at 5:11 AM
Thanks Bertrand.

I watched your video and it was a pretty complete review of how Queries work in the CMS. However, it wasn't too helpful for coding custom queries.

I searched through all the IFilterProvider implementations and it gave me some good ideas. However, I wasn't certain how the Role portion would work with the content portion so, I decided to go a different direction.

Instead, I've created an entry on the Admin menu and I'm leveraging Orchard.Users quite a bit. However, the Role portion is still biting me in the behind.

Here's a snippet of what I've been trying:
IRepository<UserRolesPartRecord> userRolesRepository;
IOrchardServices Services;

var users = Services.ContentManager.Query<UserPart, UserPartRecord>().Where(u => (userRolesRepository.Fetch(x => x.UserId == u.Id).Any(r => r.Role.Name == "MyRole")));
I wasn't too excited to use IRepository, but I went through Orchard.Roles and it looks like that's the only way to get it.

It compiles but dies with a:
NHibernate.QueryException: could not resolve property: x of: Orchard.Users.Models.UserPartRecord at NHibernate.Persister.Entity.AbstractPropertyMapping.ToType(String propertyName) ..... (plus a good 30 lines more of dump)
I'm confused since "x" is part of the Fetch from the userRolesRepository, not UserPartRecord. Now, I'm pretty sure I'm running up against my own inexperience with NHibernate and Linq. However, if that's not the way to do it, what is? I've found quite a few posts of folks with similar questions trying to get the Role of a given user, but no-one seems to have a good way of doing it.

Anyone have any good tips?

Feb 24, 2013 at 6:06 AM
So you're just trying to get all the users in a given role? That query seems a little too convoluted and inefficient. You could instead get the role by name from IRoleService.GetRoleByName, then contentManager.Query<UserRolesPart, UserRolesPartRecord>().Where(ur => ur.Role.Id == role.Id).
Feb 24, 2013 at 5:37 PM
I'm glad someone else thought so. :-) I like yours much more.

I'll give that a shot.

Feb 24, 2013 at 6:13 PM
Here's what I have:
RoleRecord role=_roleService.GetRoleByName("MyRole");
var users = Services.ContentManager.Query<UserRolesPart, UserRolesPartRecord>().Where(r => r.Role.Id == role.Id);
However, I get this:
The type 'Orchard.Roles.Models.UserRolesPart' cannot be used as type parameter 'TPart' in the generic type or method 'Orchard.ContentManagement.ContentQueryExtensions.Query<TPart,TRecord>(Orchard.ContentManagement.IContentManager)'. There is no implicit reference conversion from 'Orchard.Roles.Models.UserRolesPart' to 'Orchard.ContentManagement.ContentPart<Orchard.Roles.Models.UserRolesPartRecord>'.
I noticed I got this error before when I experimented with modifying ContentManager.Query<UserPart,UserPartRecord>() to see if I couldn't get what I wanted.

It's seeming to say that there is no connection between UserRolePart and UserRolePartRecord but that can't be right. Is there something I'm missing?

Feb 24, 2013 at 7:16 PM
Ah yes, strangely, the UserRolesPart is not a ContentPart<UserRolesPartRecord>, and UserRolesPartRecord is not a ContentPartRecord. That looks like a bug to me. Can you file it in the issue tracker?

As a workaround, you should be able to get an IRepository<UserRolesPartRecord> and then repoTable.Where(ur => ur.Role.Id == role.Id).Select(ur => ur.UserId) and then do a ContentManager.GetMany with the resulting collection of ids.
Feb 25, 2013 at 12:48 AM
Thanks Bertrand.

Yay me. My one shot at fame. :-)

Here's a snippet of what I ended up with:
//IRepository<UserRolesPartRecord> _userRolesRepository  [assigned in constructor]
//IOrchardServices_siteService  [assigned in constructor]
//IRoleService _roleService  [assigned in constructor]

RoleRecord role=_roleService.GetRoleByName("MyRole");

var users = _siteService.ContentManager
    .GetMany<UserPart>(_userRolesRepository.Table.Where(r => r.Role.Id == role.Id).Select(ur => ur.UserId), VersionOptions.Latest, QueryHints.Empty)
    .OrderBy(u => u.UserName);
Works just fine. Thanks so much for all the help.