简体   繁体   English

如何使用实体框架在C#中的多对多关系上运行linq查询

[英]How to run linq query on many-to-many relationship in c# with entity framework

I am having problems querying many-to-many relationships in Linq To Entities. 我在查询Linq To Entities中的多对多关系时遇到问题。 I am basically trying to replicate this query using Linq: 我基本上是想使用Linq复制此查询:

SELECT  
    Users.UserName, Roles.RoleName, Users.IsActive 
FROM 
    Users
LEFT JOIN 
    UserRoles ON Users.UserID = UserRoles.UserID
LEFT JOIN 
    Roles ON UserRoles.RoleID = Roles.RoleID

I tried this query in Linqpad and it works absolutely fine 我在Linqpad中尝试了此查询,它的工作原理绝对不错

Users.Join(UserRoles, u=>u.UserId, r=>r.UserId, (u,r) => new { u, r})
      .Join(Roles, ur=>ur.r.RoleId, q=>q.RoleId, (ur,q)=>new {ur, q})
      .Select(m=> new {m.ur.u.UserName, m.ur.u.IsActive, m.q.RoleName})

But when I am trying the same query in my C# application it throws an error 但是,当我在C#应用程序中尝试相同的查询时,它将引发错误

Error 错误

'Context' does not contain a definition for 'UserRoles' and no extension method 'UserRoles' accepting a first argument of type 'Context' could be found (are you missing a using directive or an assembly reference?) “上下文”不包含“ UserRoles”的定义,找不到可以接受类型为“ Context”的第一个参数的扩展方法“ UserRoles”(是否缺少using指令或程序集引用?)

My question is how to create a LINQ query in C# to retrieve Users which are assigned to Roles ? 我的问题是如何在C#创建LINQ查询以检索分配给Roles Users

My DbContext contains 我的DbContext包含

public class Context : DbContext
{
    public Context()
        : base("Name=xyz")
    {
        if (!Database.Exists("xyz"))
            Database.SetInitializer(new Initializer());
    }
    public DbSet<User> Users { get; set; }
    public DbSet<Role> Roles { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new UserMap());

        base.OnModelCreating(modelBuilder);
    }
}

public class UserMap : EntityTypeConfiguration<User>
{
    public UserMap()
    {
        HasMany(r => r.Roles).WithMany(u=>u.Users)
            .Map(m =>
            {
                m.ToTable("UserRoles");
                m.MapLeftKey("UserId");
                m.MapRightKey("RoleId");
            });
    }
}

public class User
{
    public User()
    {
        this.Roles = new HashSet<Role>();
    }
    public int UserId { get; set; }
    public string UserName { get; set; }
    public string PasswordHash { get; set; }
    public DateTime? LastLoggedOn { get; set; }
    public DateTime? PasswordChangedOn { get; set; }
    public int IsActive { get; set; }

    public virtual ICollection<Role> Roles { get; set; }
}

public class Role
{
    public Role()
    {
        this.Users = new HashSet<User>();
    }
    public int RoleId { get; set; }
    public string RoleName { get; set; }
    public string Description { get; set; }

    public virtual ICollection<User> Users { get; set; }
}

EDIT: Looking at the code in the question: there is no UserRoles defined. 编辑:查看问题中的代码:没有定义UserRoles You need to refactor in terms of EF knowing the many-many relationship: 您需要根据EF来了解多对多关系,从而进行重构:

var res = db.Users.SelectMany(u => 
                  u.Roles.Select(r =>
                      new {
                        u.UserName,
                        r.RoleName,
                        u.IsActive
                      }
                  )
          );

EF understands (because you've defined it) how to do the join: The Roles collection – representing the relationship – will filter on only the roles belonging to the user that you start with. EF理解(因为已经定义了)如何进行联接:代表关系的Roles集合将仅根据属于您的用户的角色进行过滤。


Original Answer 原始答案

In what type is the definition of the method in which you write the query? 编写查询的方法的定义是哪种类型?

LINQpad (IIRC) runs everything as if it were a method of your DbContext derived type. LINQpad(IIRC)像运行DbContext派生类型的方法一样运行所有内容。 Thus the DbSet<T> properties mapping tables are usable without qualification (in your case UserRoles ). 因此, DbSet<T>属性映射表无需限定即可使用(在您的情况下为UserRoles )。 If not a member of your context type you need to qualify the entity sets with an instance of the context: 如果您不是上下文类型的成员,则需要使用上下文的实例来限定实体集:

using (var db = new MyContext()) {
  var data = db.Users.Join(db.UserRoles, u=>u.UserId, r=>r.UserId, (u,r) => new { u, r})
               .Join(db.Roles, ur=>ur.r.RoleId, q=>q.RoleId, (ur,q)=>new {ur, q})
               .Select(m=> new {m.ur.u.UserName, m.ur.u.IsActive, m.q.RoleName})
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM