简体   繁体   English

Linq查询返回复杂类型

[英]Linq Query To Return Complex Type

I have a pretty standard model for Users and Roles: 我有一个非常标准的用户和角色模型:

+-------+   +-----------+   +-------+
| Users |   | UserRoles |   | Roles |
+-------+   +-----------+   +-------+
| ID (P)| < | UserID (P)|   | ID (P)|
| ...   |   | RoleID (P)| > | ...   |
+-------+   +-----------+   +-------+

I am using the Entitiy framework as my ORM and I am trying to construct - in a single Linq query - my ViewModel, definied below: 我使用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; }
}

I figured that the following query should work: 我认为以下查询应该有效:

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

However, this throws the following error: 但是,这会引发以下错误:

LINQ to Entities does not recognize the method 'System.Collections.Generic.List [RolesRepository+RoleDetail+RoleUser] ToList[RoleUser] (System.Collections.Generic.IEnumerable[RolesRepository+RoleDetail+RoleUser])' method, and this method cannot be translated into a store expression. LINQ to Entities无法识别方法'System.Collections.Generic.List [RolesRepository + RoleDetail + RoleUser] ToList [RoleUser](System.Collections.Generic.IEnumerable [RolesRepository + RoleDetail + RoleUser])'方法,而且这个方法不能被翻译成商店表达。

I haven't worked with Linq a lot, so I am quite sure that my query is wrong somehow. 我没有和Linq一起工作过,所以我很确定我的查询在某种程度上是错误的。 Can someone show me where my query is going wrong and if there is a better way to accompish what I'm trying to achieve? 有人可以告诉我我的查询出错的地方,以及是否有更好的方法来实现我想要实现的目标?

Thank you in advance! 先感谢您!

Little experience with linq-to-entities, so this is a shot in the dark: 对linq-to-entities的经验很少,所以这是一个黑暗中的镜头:

Why do you need .ToList()? 你为什么需要.ToList()?

.Select() already returns an IEnumerable, so it should work without. .Select()已经返回一个IEnumerable,所以它应该没有。

ToList() returns a List, not an IList or similar interface, but a concrete c# class. ToList()返回一个List,而不是一个IList或类似的接口,而是一个具体的c#类。 So I'd imagine that Linq to Entities cannot translate that into its own behind the scenes syntax 因此,我认为Linq to Entities无法将其转换为自己的幕后语法

Does this work? 这有用吗?

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

Everything in your LINQ query that gets sent off to the EF LINQ provider needs to be an expression that L2E can translate into SQL directly. LINQ查询中发送到EF LINQ提供程序的所有内容都需要是L2E可以直接转换为SQL的表达式。 It's up to you to manually separate the parts that EF can translate, from the parts that have to be done in LINQ 2 Objects. 您可以手动分离EF可以翻译的部分,以及必须在LINQ 2对象中完成的部分。

The execution happens at the point where the query has to be actually enumerated, which in your case is the FirstOrDefault call. 执行发生在必须实际枚举查询的位置,在您的情况下是FirstOrDefault调用。 You can force the query to be executed earlier by calling IQueryable.AsEnumerable() ; 您可以通过调用IQueryable.AsEnumerable()来强制执行查询。 anything after that is processed by LINQ 2 Objects and can pretty much do whatever you want. 之后的任何事情都由LINQ 2对象处理,几乎可以做任何你想做的事情。

In your case, the only non-translatable aspect of your lambda expression is the call to ToList , which has no database equivalent, so you could simply not call that; 在你的情况下,lambda表达式唯一不可翻译的方面是对ToList的调用,它没有数据库等价物,所以你根本就不能调用它; the downside to this is that your Users property will be set up some arbitrary internal class that happens to be the result of IQueryable.Select in the EF's implementation. 这样做的缺点是你的Users属性将设置一些任意内部类,恰好是EF的实现中IQueryable.Select的结果。 That may or may not be a problem for you, depending on what you defined RoleDetail.Users as and what you do with it. 这对您来说可能是也可能不是问题,具体取决于您对RoleDetail.Users定义以及您使用它做了什么。

The alternative, and the more generally-applicable solution when you have to process an expression that EF doesn't like, is to insert the AsEnumerable call early: 当您必须处理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();

Looks like it's trying to execute ToList at the database and not knowing how. 看起来它试图在数据库中执行ToList而不知道如何。 I would try changing it to ToArray , or failing that, just leaving it as IEnumerable. 我会尝试将其更改为ToArray ,或者失败,只需将其保留为IEnumerable。

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

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