【问题标题】:Cant use Linq WHERE/IN/JOIN with Entity Framework on many to many不能在多对多上使用带有实体框架的 Linq WHERE/IN/JOIN
【发布时间】:2014-11-20 10:58:11
【问题描述】:

我可以在 SQL 中非常简单地做到这一点,但尝试学习如何在 Linq 中使用 Entity Framework 做到这一点。

我有一个用户,一个用户可以有多个组,一个组可以有多个权限。

我想获得一个用户的所有权限。

我的 DbContext 中有以下 DbSet

public virtual DbSet<User> Users { get; set; }
public virtual DbSet<Group> Groups { get; set; }
public virtual DbSet<Permission> Permissions { get; set; }

还有类是这样的

public class User : Entity, IUser<long>
{
    public string UserName { get; set; }

    public string PasswordHash { get; set; }

    public User()
        : base()
    {
        this.Groups = new HashSet<UserGroup>();
    }

    public virtual ICollection<UserGroup> Groups { get; set; }
}

public class Group : AuditableEntity
{
    public Group() {
        this.Permissions = new HashSet<GroupPermission>();            
    }

    public string Name { get; set; }

    public virtual ICollection<GroupPermission> Permissions { get; set; }
}

public class Permission 
{
    public string Name { get; set; }

    public Permission()
    {

    }
}

为了处理多对多的关系,我也有这些类

public class UserGroup
{

    public long UserId { get; set; }
    public long GroupId { get; set; }

    public virtual User User { get; set; }
    public virtual Group Group { get; set; }

}

public class GroupPermission
{
    public long PermissionId { get; set; }
    public long GroupId { get; set; }

    public virtual Permission Permission { get; set; }
    public virtual Group Group { get; set; }
}

现在在 SQL 中我会简单地做

SELECT Permission.* 
FROM Permission
    INNER JOIN PermissionGroup ON Permission.Id = PermissionGroup.PermissionId
    INNER JOIN Group ON PermissionGroup.GroupId = Group.Id
    INNER JOIN UserGroup ON Group.Id = UserGroup.GroupId
WHERE UserGroup.UserId = @UserId

有人可以告诉我为什么我不能在 LINQ 中这样做吗?好吧,我知道我可以,但我不知道怎么做。

编辑

context.PermissionGroup 和 context.UserGroup 在我的上下文中不是 DbSet。

List<Permission> result;
using(DataContext context = new DataContext())
{
   result = (from permission in context.Permissions
             join permissionGroup in context.PermissionGroup on permission.Id equals permissionGroup.Id
             join g in context.Groups on permissionGroup.GroupId equals g.Id
             join userGroup in context.UserGroup on g.Id equals userGroup.GroupId
             where userGroup.UserId == user.Id 
             select permission).ToList();
}

【问题讨论】:

    标签: c# asp.net .net linq entity-framework


    【解决方案1】:

    使用这个

    var linqQuery=(from p in Permission
                        join pg in PermissionGroup on p.Id equals pg.Id
                        join g in Group on pg.GroupId equals g.Id
                        join ug in UserGroup on g.Id equals ug.GroupId
                        where ug.UserId == USERID 
                        select p);
    

    【讨论】:

    • 您从哪里获得 PermissionGroup 和 UserGroup?如果 _context 是我的 DbContext,我没有引用名为 PermissionGroup 或 UserGroup 的 DbSet??
    • 创建一个 Dbcontext 引用,比如 ctx 并将其用作 ctx.Permission、ctx.PermissionGroup、ctx.Group 和 ctx.UserGroup
    • 那甚至无法编译。说没有提到 ctx.Permission 等,添加到我的原始帖子中
    • 完成编辑。请检查我的原始类定义和我的 DbContext。我已经说过我有哪些 DbSet。 userGroup 由称为 Groups 的 User 类引用。而 GroupPermission 由 Group 类称为 Permissions
    【解决方案2】:

    加入 SQL 并不意味着您应该加入 LINQ。尽可能使用导航属性。如果您这样做,您的情况会变得更简单,并为此使用SelectMany

    from u in db.Users
    select new { 
                 u.UserName,
                 Permissions = u.Groups
                                .Select(ug => ug.Group)
                                .SelectMany(g => g.Permissions)
                                .Select(gp => gp.Permission
               }
    

    【讨论】:

    • 好吧,我确实在上面问过我是否需要为每个表连接添加一个 DbSet 到我的上下文中,但被告知我应该。我很乐意使用您的代码,因为我有导航属性(如您所见),但您的代码不起作用。代码中不存在权限g => g.Permissions,g会返回一个UserGroup,它有UserId、User、GroupId、Group的属性
    • 好的,这看起来很有希望,但是如果我已经将用户作为参数呢?因此,我将如何修改您的代码,而不是 db.Users?基本上我有一个接受用户的函数,我想返回那里的权限。还是这不可能?
    • 你可以简单的添加一个wherefrom u in db.Users where u.UserName == user.UserName,其中user是进入函数的用户,并且假设UserName是唯一的。 (我没有看到主键属性,但您可能希望按该属性进行过滤)。
    • 是的,我最后也是这么想的。谢谢,将您的标记为答案,因为您回答了我最初想要的内容
    【解决方案3】:

    如果您有自己的DbContext 类,其中所有数据库表都表示为DbSets

    public partial class OwnContext: DbContext
    {
       public DbSet<User> Users { get; set; }
       public DbSet<Group> Groups { get; set; }
       public DbSet<Permission> Permissions { get; set; }
       public DbSet<UserGroup> UserGroups { get; set; }
       public DbSet<PermissionGroup> PermissionGroups { get; set; }
    }
    

    您必须使用 using 语句创建该类的实例,并在 using 语句中执行您的查询。

    List<Permission> result;
    using(OwnContext context = new OwnContext())
    {
       result = (from permission in context.Permissions
                 join permissionGroup in context.PermissionGroups on permission.Id equals permissionGroup.Id
                 join group in context.Groups on permissionGroup.GroupId equals group.Id
                 join userGroup in context.UserGroups on group.Id equals userGroup.GroupId
                 where userGroup.UserId == user.Id 
                 select permission).ToList();
    }
    

    【讨论】:

    • 不,这不起作用。来自权限中的 p 有错误“找不到源类型“my.name.space.Permission”的查询模式的实现“未找到‘加入’。在 PermissionGroup 中加入 pg 有错误“名称‘PermissionGroup’不存在于当前上下文”在组中加入 g 并在用户组中加入 ug 有错误“my.name.space.Group/UserGroup 是一种被用作变量的类型”将我的确切代码复制到问题帖子中。
    • @user2736022 你有对“System.Linq”的引用吗?
    • 您编辑了答案,哈哈。仍然没有工作,但更接近。是的,我引用了 System.Linq。但是 context.PermissionGroup 和 context.UserGroup 在我的上下文中不是 DbSet。我已经再次更新了我的代码,因为你放的是 context.Permission 而不是 context.Permissions,请参阅我的代码
    • @user2736022 哦,现在我明白了。 :) 你能把 PermissionGroup 和 UserGroup 添加到你的 DbContext 吗?
    • 我也应该有吗?当然,您不需要将每个关系连接添加为 DbContext 中的 dbSet。我不介意我是否必须通过几个 linq 查询而不是 1
    【解决方案4】:
    using (var context = new NombreDeEntityDataModel)
    {
        var query = from a in context.Permission
                    join b in context.PermissionGroup on a.id equals b.PermissionId
                    join c in context.Group on b.GroupId equals c.id
                    join d in context.UserGroup on c.id equals d.GroupId
                    where d.UserId = @UserId
                    select a;
    }
    

    【讨论】:

    • 我没有 context.PermissionGroup,也没有 context.UserGroup 作为我的上下文中的 DbSet。仅作为对象的导航属性
    猜你喜欢
    • 1970-01-01
    • 2017-06-15
    • 2020-07-19
    • 1970-01-01
    • 2011-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-20
    相关资源
    最近更新 更多