繁体   English   中英

Linq查询返回复杂类型

[英]Linq Query To Return Complex Type

我有一个非常标准的用户和角色模型:

+-------+   +-----------+   +-------+
| 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一起工作过,所以我很确定我的查询在某种程度上是错误的。 有人可以告诉我我的查询出错的地方,以及是否有更好的方法来实现我想要实现的目标?

先感谢您!

对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();

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();

看起来它试图在数据库中执行ToList而不知道如何。 我会尝试将其更改为ToArray ,或者失败,只需将其保留为IEnumerable。

暂无
暂无

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

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