How do I query many-to-many mapping in EF4?

孤街浪徒 提交于 2019-12-11 04:23:37

问题


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:

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.


回答1:


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));
}



回答2:


Try this:

var result = _userRepository
              .Where(u => u.Id == userId)
              .SelectMany(u => u.Roles)
              .Where(r => r.Id == roleId)
              .SingleOrDefault();
return result != null;



回答3:


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();


来源:https://stackoverflow.com/questions/5228481/how-do-i-query-many-to-many-mapping-in-ef4

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!