[英]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.