I have a pretty simple problem with a not-so-obvious solution. I have a relational mapping in my database between Users and Roles, and each user can be mapped to one or more roles. So the mapping is like so:
User < 1:n > UserRole < n:1 > Role
In my generated EF4 POCOs, User and Role each have an ICollection of the other:
public class User
{
//Bunch of other properties/methods
public virtual ICollection<Role> Roles
}
public class Role
{
//Bunch of other properties/methods
public virtual ICollection<User> Users
}
Now, I've implemented the IoC, UoW, and repository patterns illustrated in this article, which uses an ObjectSet to fetch/persist the data via repositories.
My question is, how do I implement this:
public bool UserIsInRole(int userId, int roleId)
I have tried the following:
public bool UserIsInRole(int userId, int roleId)
{
Role role = _roleRepository.Single(r => r.Id == roleId);
return _userRepository.SingleOrDefault(u => u.Roles.Contains(role)) != null;
}
But it fails with:
Unable to create a constant value of type 'Data.Models.Role'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
Plus, it's not a very elegant implementation as it's having to hit the database twice.
I was looking for something like this:
开发者_JAVA技巧return _userRepository.SingleOrDefault(u => u.Roles.Where(r => r.Id = roleId));
But ICollection doesn't support LINQ.
How can I do this, and ideally, how can I do it with one LINQ expression and one trip to the database?
Or, am I going about this completely wrong?
Thanks in advance.
Solved: Thanks to all who posted. All gave an acceptable answer. I accepted the one that was the most elegant.
There is a more concise way to do it:
public bool UserIsInRole(int userId, int roleId)
{
return _userRepository.
Any(u => u.Id == userId &&
u.Roles.Any(r => r.Id == roleId));
}
Try this:
var result = _userRepository
.Where(u => u.Id == userId)
.SelectMany(u => u.Roles)
.Where(r => r.Id == roleId)
.SingleOrDefault();
return result != null;
If I understand correctly you are trying to select all of the users in a specific role.
If that is the case then:
public bool UserIsInRole(int userId, int roleId){
var user = (from u in _userRepository where u.Id == userId select u).SingleOrDefult();
if (user != null)
{
return (from r in user.Roles where r.Id = roleId select r).Any();
}
//you may not want to do this if you couldn't find the passed in user.
return false;
}
You still have to hit the database twice but both of the queries should be pretty small.
Since you say, in comments, that you already have the user that you want to use the above method should still work. I was about to write something to explain how you could do it using the repository pattern that is mentioned in the article but at the surface it isn't function any differently than using a context would, at least for querying.
Since you are passing in a the User.Id
as userId
and not a complete User
you still need to query for the appropriate user.
Now we can shorten the query some with
return _userReposity.Where(u => u.Id == userId)
.SelectMany(u => u.Roles)
.Where(r => r.id == roleId)
.SingleOrDefault() != null;
Or Alternatively
return (from u in _userRepository
from r in u.Roles
Where u.Id == userId && r.Id = roleId
Select r).Any();
精彩评论