如何在 EF4 中查询多对多映射?

发布于 2024-10-20 13:17:26 字数 1490 浏览 6 评论 0原文

我有一个非常简单的问题,但解决方案并不那么明显。我的数据库中有一个用户和角色之间的关系映射,每个用户可以映射到一个或多个角色。所以映射就像这样:

用户< 1:n>用户角色 < n:1>角色

在我生成的 EF4 POCO 中,用户和角色各自都有另一个的 ICollection:

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
}

现在,我已经实现了 本文,它使用 ObjectSet 通过存储库获取/保存数据。

我的问题是,如何实现这个

public bool UserIsInRole(int userId, int roleId)

我已尝试以下操作:

public bool UserIsInRole(int userId, int roleId)
{
    Role role = _roleRepository.Single(r => r.Id == roleId);
    return _userRepository.SingleOrDefault(u => u.Roles.Contains(role)) != null;
}

但失败了:

无法创建“Data.Models.Role”类型的常量值。此上下文仅支持原始类型(“例如 Int32、String 和 Guid”)。

另外,它不是一个非常优雅的实现,因为它必须访问数据库两次。

我一直在寻找这样的东西:

return _userRepository.SingleOrDefault(u => u.Roles.Where(r => r.Id = roleId));

但 ICollection 不支持 LINQ。

我该如何做到这一点?理想情况下,如何通过一个 LINQ 表达式和一次数据库访问来实现这一点?

或者,我的做法完全错误吗?

提前致谢。

已解决: 感谢所有发帖的人。大家都给出了可以接受的答案。我接受了最优雅的那一个。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

祁梦 2024-10-27 13:17:27

试试这个:

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

Try this:

var result = _userRepository
              .Where(u => u.Id == userId)
              .SelectMany(u => u.Roles)
              .Where(r => r.Id == roleId)
              .SingleOrDefault();
return result != null;
凉城 2024-10-27 13:17:27

如果我理解正确的话,您正在尝试选择特定角色的所有用户。

如果是这种情况,那么:

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

您仍然需要访问数据库两次,但两次查询都应该非常小。


既然您在评论中说您已经拥有要使用上述方法的用户,那么上述方法应该仍然有效。我本来打算写一些东西来解释如何使用文章中提到的存储库模式来做到这一点,但从表面上看,它的功能与使用上下文没有任何不同,至少对于查询来说是这样。

由于您将 User.Id 作为 userId 传递,而不是完整的 User,因此您仍然需要查询适当的用户。

缩短一些查询

return _userReposity.Where(u => u.Id == userId)
                    .SelectMany(u => u.Roles)
                    .Where(r => r.id == roleId)
                    .SingleOrDefault() != null;

现在我们可以使用Or Alternative 来

return (from u in _userRepository
        from r in u.Roles
        Where u.Id == userId && r.Id = roleId
        Select r).Any();

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();
看轻我的陪伴 2024-10-27 13:17:26

有一种更简洁的方法可以做到这一点:

public bool UserIsInRole(int userId, int roleId)
{
    return _userRepository.
            Any(u => u.Id == userId && 
                     u.Roles.Any(r => r.Id == roleId));
}

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));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文