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

Pau*_*hra 6 c# linq linq-to-entities entity-framework

为什么一个方法可以工作而不是另一个方法,当它们看起来都在做同样的事情时,即构建一个实体.那么我的问题是,有没有办法在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();
Run Code Online (Sandbox Code Playgroud)

但是,如果我改变......

var queryToList
Run Code Online (Sandbox Code Playgroud)

model.AuthorisationChecks queryToList // Of type List<AuthorisationCheck>
Run Code Online (Sandbox Code Playgroud)

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

The entity or complex type 'Model.AuthorisationCheck' cannot be constructed in a LINQ to Entities query.
Run Code Online (Sandbox Code Playgroud)

编辑: 在模型中它很简单,没有什么花哨的.

public List<AuthorisationCheck> AuthorisationChecks { get; set; }
Run Code Online (Sandbox Code Playgroud)

编辑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();
Run Code Online (Sandbox Code Playgroud)

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

改变了模型的类型.授权检查

List<AuthorisationCheck> // List of Entities
Run Code Online (Sandbox Code Playgroud)

List<AuthorisationCheckModel> // List of models
Run Code Online (Sandbox Code Playgroud)

它允许以下代码工作,并且没有分析它似乎比使用匿名类型快得多(当然我不会两次强制转换为列表!).

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();
Run Code Online (Sandbox Code Playgroud)

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

Fla*_*ter 5

注意:我通常使用 lambda 表达式而不是 Fluent API,但根本问题应该是相同的。

我以前注意到,如果通过将查询转换为 SQL 来访问原始数据源(即ctx对于您而言),则 LINQ 无法将 C# 类用于 Select 语句。

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

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

List<>您通常可以通过首先创建数据库表,然后对其运行完全相同的查询来确认情况是否如此。

var myTable = db.AuthorizationCheck.ToList();

var myResult = myTable. //query here
Run Code Online (Sandbox Code Playgroud)

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

我已经解决了这个问题,尽管我从未找到解决此问题的统一方法(通常取决于我的代码审阅者的意见,无论他是否喜欢修复)

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

//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();
Run Code Online (Sandbox Code Playgroud)

如果您使用 lambda 表达式而不是 Fluent API,则可以在应用过滤器之后但.ToList() 调用方法之前.Select()进行调用。这确保当前查询将被执行、从数据库中检索并放入实际的List<>内存中。此时,您可以调用该.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 });
Run Code Online (Sandbox Code Playgroud)

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

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


Ehs*_*jad 3

如果这个查询工作正常:

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();
Run Code Online (Sandbox Code Playgroud)

那么这也应该有效:

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();
Run Code Online (Sandbox Code Playgroud)

在第一种情况下,您不需要再次投影,可以直接将其分配给模型属性:

model.AuthorisationChecks = queryToList;
Run Code Online (Sandbox Code Playgroud)

更新:

由于它是 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();
Run Code Online (Sandbox Code Playgroud)

进而:

model.AuthorisationChecks = queryToList.Select(x => new AuthorisationCheck
    {
        Blah = x.Blah
    }).ToList();
Run Code Online (Sandbox Code Playgroud)