实体或复杂类型...无法在 LINQ to Entities 查询中构造

The entity or complex type ... cannot be constructed in a LINQ to Entities query

为什么一种方法有效而另一种方法无效,因为它们似乎都在做同样的事情,即构建一个实体。那么我的问题是,有没有一种方法可以在 L2E 查询中构建实体,而不必仅使用 Linq 或两者兼而有之?

这很好用...

var queryToList = (from ac in ctx.AuthorisationChecks
                   where wedNumbers.Contains(ac.WedNo)
                   orderby ac.WedNo, ac.ExpAuthDate, ac.ActAuthDate
                   select new AuthorisationCheck
                   {
                       Blah = ac.Blah
                   }).ToList();

model.AuthorisationChecks = queryToList.Select(x => new AuthorisationCheck
    {
        Blah = x.Blah
    }).ToList();

但是,如果我改变...

var queryToList

model.AuthorisationChecks queryToList // Of type List<AuthorisationCheck>

我得到标题中的错误...

The entity or complex type 'Model.AuthorisationCheck' cannot be constructed in a LINQ to Entities query.

编辑: 在模型中很简单,这里没什么特别的。

public List<AuthorisationCheck> AuthorisationChecks { get; set; }

编辑2: 稍微整理一下(效果很好)...

model.AuthorisationChecks = (from ac in ctx.AuthorisationChecks
                             where wedNumbers.Contains(ac.WedNo)
                             orderby ac.WedNo, ac.ExpAuthDate, ac.ActAuthDate
                             select ac).ToList()
                             .Select(x => new AuthorisationCheck
                             {
                                 Blah = x.Blah
                             }).ToList();

EDIT2:我的解决方案 我对匿名类型方法不满意,所以继续创建了一个简单的模型,其中只包含我需要在视图模型中使用的属性。

更改了 model.AuthorisationChecks

的类型

来自

List<AuthorisationCheck> // List of Entities

List<AuthorisationCheckModel> // List of models

它允许下面的代码工作,并且在没有分析的情况下它似乎比使用匿名类型快得多(当然我不会两次转换到列表!)。

model.AuthorisationChecks = (from ac in ctx.AuthorisationChecks
                             where wedNumbers.Contains(ac.WedNo)
                             orderby ac.WedNo, ac.ExpAuthDate, ac.ActAuthDate
                             select new AuthorisationCheckModel
                             {
                                 Blah = x.Blah
                             }).ToList();

P.S。我曾经被一位同事(曾经为微软工作)警告过,以这种方式直接使用实体不是一个好主意,也许这是他考虑的原因之一,我也注意到一些奇怪的在其他情况下直接使用实体的行为(主要是腐败)。

如果此查询工作正常:

var queryToList = (from ac in ctx.AuthorisationChecks
                   where wedNumbers.Contains(ac.WedNo)
                   orderby ac.WedNo, ac.ExpAuthDate, ac.ActAuthDate
                   select new AuthorisationCheck
                   {
                       Blah = ac.Blah
                   }).ToList();

那么这也应该有效:

model.AuthorisationChecks = (from ac in ctx.AuthorisationChecks
                   where wedNumbers.Contains(ac.WedNo)
                   orderby ac.WedNo, ac.ExpAuthDate, ac.ActAuthDate
                   select new AuthorisationCheck
                   {
                       Blah = ac.Blah
                   }).ToList();

而你第一种情况不需要再投影,直接赋值给模型属性即可:

model.AuthorisationChecks = queryToList;

更新:

因为它是 Linq To Entities,你必须使用匿名类型做这样的事情:

var queryToList = (from ac in ctx.AuthorisationChecks
                       where wedNumbers.Contains(ac.WedNo)
                       orderby ac.WedNo, ac.ExpAuthDate, ac.ActAuthDate
                       select new 
                       {
                           Blah = ac.Blah
                       }).ToList();

然后:

model.AuthorisationChecks = queryToList.Select(x => new AuthorisationCheck
    {
        Blah = x.Blah
    }).ToList();

注意:我一般使用lambda表达式而不是FluentAPI,但根本问题应该是一样的

我一直注意到 LINQ 无法将 C# classes 用于 Select 语句 如果原始数据源(即 ctx 对于you) 通过将您的查询翻译成 SQL.

来访问

换句话说,从数据库 将其转换为同一链中的自定义 class 时存在问题。

LINQ 足够聪明,它实际上不会立即执行您的链式调用。它只是在内部构建一个查询,当您实际访问结果时(即从内存中检索值),它会执行查询。
我认为这也是您遇到此错误的原因,因为 LINQ 将所有内容(包括 Select)转换为 SQL,但由于没有 SQL 表达方式而失败.简而言之,LINQ 不能做一个构建的查询 half-SQL,half-code。它要么全部在 SQL 中,要么全部在代码中。

您通常可以通过首先对数据库 table 进行 List<>,然后对数据库进行 运行 完全相同的查询来确认是这种情况。

var myTable = db.AuthorizationCheck.ToList();

var myResult = myTable. //query here

注意:这不是解决方案!
将整个 table 放入内存是一种过于密集的解决方法。只是证明数据源在内存中不会出现问题,在数据库中就会出现这个问题。

虽然我从来没有找到解决这个问题的统一方法(通常取决于我的代码审阅者的意见,他是否喜欢这个修复)

使用匿名类型,您可以select您想要的,然后将其转换为正确的class。您可以使用完全相同的字段,使以后的转换更容易理解。

//Simpler query for clarity's sake
var myAnonymousResult = ctx.AuthorizationChecks
                                .Where(x => x.IsActive)
                                .Select(x => new { Name = x.Name, IsActive = x.IsActive })
                                .ToList();

var myCastResult = myAnonymousResult.Select(x => new Check() { Name = x.Name, IsActive = x.IsActive }).ToList();

如果你使用lambda表达式而不是流畅的API,你可以在应用后调用.ToList()过滤器,但 before 调用 .Select() 方法。这确保当前查询将被执行,从数据库中检索,并放入内存中的实际 List<> 中。到那时,您可以调用 .Select() 语句而无需 运行ning 进入相同的问题。

//Simpler query for clarity's sake
var myCastResult = ctx.AuthorizationChecks
                                .Where(x => x.IsActive)
                                .ToList()
                                .Select(x => new Check() { Name = x.Name, IsActive = x.IsActive });

不幸的是,我在这个问题上的经历是轶事。我一直无法正式证实我对这个问题的根本原因的怀疑;但我提到的解决方法应该有效,因为我过去已经多次应用它们。

如果有人能解释根本原因,我会很想听听的!