用于返回复杂类型的 Linq 查询
本文关键字:Linq 查询 类型 返回 复杂 用于 | 更新日期: 2023-09-27 18:32:38
我有一个非常标准的用户和角色模型:
+-------+ +-----------+ +-------+
| 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 实体无法识别该方法 'System.Collections.Generic.List [RolesRepository+RoleDetail+RoleUser] 待列表[角色用户] (System.Collections.Generic.IEnumerable[RolesRepository+RoleDetail+RoleUser](' 方法,并且此方法无法转换为存储表达式。
我没有经常使用 Linq,所以我很确定我的查询以某种方式是错误的。 有人可以告诉我我的查询哪里出了问题,以及是否有更好的方法来弥补我想要实现的目标?
提前谢谢你!
对 linq-to-entity 几乎没有经验,所以这是一个黑暗中的镜头:
你为什么需要.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();
查询中发送到 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();
看起来它正在尝试在数据库中执行 ToList,但不知道如何执行。 我会尝试将其更改为ToArray,或者失败,只是将其保留为IEnumerable。