【问题标题】:The entity or complex type ... cannot be constructed in a LINQ to Entities query实体或复杂类型...不能在 LINQ to Entities 查询中构造
【发布时间】:2015-03-11 11:12:33
【问题描述】:

为什么一种方法有效而另一种无效,当它们似乎都在做同样的事情时,即构建一个实体。那么我的问题是,有没有办法在 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; }

EDIT2: 稍微整理了一下(效果很好)...

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

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

【问题讨论】:

  • 你必须写model.AuthorisationChecks =
  • 顺便说一句,它更快,因为在您的第一个查询中,您首先选择所有列,然后仅将 1 分配给您的新对象,您的最后一个查询仅选择 1 列

标签: c# linq entity-framework linq-to-entities


【解决方案1】:

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

我曾经注意到 LINQ 无法将 C# 类用于 Select 语句如果原始数据源(即您的 ctx通过将您的查询转换为 SQL 来访问 >.

换句话说,从数据库中获取某些内容将其转换为同一链中的自定义类时会出现问题。

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

您通常可以通过首先创建数据库表的List&lt;&gt;,然后对其运行完全相同的查询来确认是这种情况。

var myTable = db.AuthorizationCheck.ToList();

var myResult = myTable. //query here

注意:这不是解决方案!
将整个表放入内存是解决此问题的一种过于密集的方法。它只是证明如果数据源在内存中则不会遇到问题,但如果它在数据库中则确实会发生错误。

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

使用匿名类型,您可以选择所需的内容,然后将其转换为正确的类。您可以使用完全相同的字段,使以后的演员更容易理解。

//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 表达式而不是 fluent API,您可以在应用过滤器之后调用 .ToList() 但在调用 @ 之前之前 987654326@ 方法。这确保了当前查询将被执行,从数据库中检索,并放入内存中的实际List&lt;&gt;。此时,您可以调用.Select() 语句而不会遇到同样的问题。

//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 });

不幸的是,我对这个问题的经验是轶事。我一直无法正式证实我对这个问题的根本原因的怀疑;但我提到的解决方法应该可以工作,因为我过去曾多次应用它们。

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

【讨论】:

  • 您这里使用的是中间模型吗?新检查()
  • 不具体。我使用了一个带有简单字段的简单示例来演示这个想法。通过适合您的案例的类和字段来更改类和字段。
【解决方案2】:

如果此查询正常:

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

【讨论】:

  • 啊,很好发现...模型上的愚蠢错误。AuthorisationChecks = ...但它仍然给我同样的错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-11
  • 2017-05-31
  • 2015-02-06
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
相关资源
最近更新 更多