我有一个非常标准的用户和角色模型:
+-------+ +-----------+ +-------+
| Users | | UserRoles | | Roles |
+-------+ +-----------+ +-------+
| ID (P)| < | UserID (P)| | ID (P)|
| ... | | RoleID (P)| > | ... |
+-------+ +-----------+ +-------+
我正在使用Entitiy框架作为我的ORM,我正在尝试构建 - 在单个Linq查询中 - 我的ViewModel,定义如下:
public class RoleDetail {
public class RoleUser {
public int ID { get; set; }
public string Username { get; set; }
}
public int ID { get; set; }
public string Rolename { get; set; }
public bool Active { get; set; }
public IEnumerable<RoleUser> Users { get; set; }
}
我认为以下查询应该有效:
var query = Context.Roles
.Include("Users")
.Where(r => r.ID == id)
.Select(r => new RoleDetail() {
ID = r.ID,
Rolename = r.Rolename,
Active = r.Active,
Users = r.Users
.Select(u => new RoleDetail.RoleUser() {
ID = u.ID,
Username = u.Username
})
.ToList()
})
.FirstOrDefault();
但是,这会引发以下错误:
LINQ to Entities无法识别该方法 'System.Collections.Generic.List [RolesRepository + RoleDetail + RoleUser] ToList [RoleUser] (System.Collections.Generic.IEnumerable [RolesRepository + RoleDetail + RoleUser])” 方法,并且此方法无法转换为商店表达式。
我没有和Linq合作过很多,所以我很确定我的查询在某种程度上是错误的。有人可以告诉我我的查询出错的地方,以及是否有更好的方法来实现我想要实现的目标?
提前谢谢!
答案 0 :(得分:2)
对linq-to-entities的经验很少,所以这是一个黑暗中的镜头:
为什么需要.ToList()?
.Select()已经返回一个IEnumerable,所以它应该没有。
ToList()返回一个List,而不是一个IList或类似的接口,而是一个具体的c#类。因此,我认为Linq to Entities无法将其转换为自己的幕后语法
这有用吗?
var query = Context.Roles
.Include("Users")
.Where(r => r.ID == id)
.Select(r => new RoleDetail() {
ID = r.ID,
Rolename = r.Rolename,
Active = r.Active,
Users = r.Users
.Select(u => new RoleDetail.RoleUser() {
ID = u.ID,
Username = u.Username
})
// .ToList()
})
.FirstOrDefault();
答案 1 :(得分:2)
LINQ查询中发送到EF LINQ提供程序的所有内容都需要是L2E可以直接转换为SQL的表达式。您可以手动分离EF可以翻译的部分,以及必须在LINQ 2对象中完成的部分。
执行发生在必须实际枚举查询的位置,在您的情况下是FirstOrDefault
调用。您可以通过调用IQueryable.AsEnumerable()
来强制执行查询;之后的任何事情都由LINQ 2对象处理,几乎可以随心所欲。
在你的情况下,lambda表达式唯一不可翻译的方面是对ToList
的调用,它没有数据库等价物,所以你根本就不能调用它;这样做的缺点是你的Users
属性将被设置为一些任意内部类,恰好是EF实现中IQueryable.Select
的结果。对您而言,这可能是也可能不是问题,具体取决于您对RoleDetail.Users
的定义以及您使用它做了什么。
当您必须处理EF不喜欢的表达式时,替代方案以及更普遍适用的解决方案是提前插入AsEnumerable
调用:
var query = Context.Roles
.Include("Users")
.Where(r => r.ID == id)
.AsEnumerable()
.Select(r => new RoleDetail() {
ID = r.ID,
Rolename = r.Rolename,
Active = r.Active,
Users = r.Users
.Select(u => new RoleDetail.RoleUser() {
ID = u.ID,
Username = u.Username
})
// .ToList()
})
.FirstOrDefault();
答案 2 :(得分:1)
看起来它正在尝试在数据库中执行 ToList 而不知道如何执行。我会尝试将其更改为 ToArray ,或者将其更改为失败,只需将其保留为IEnumerable。