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

时间:2015-03-11 11:12:34

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

为什么一种方法可以工作而另一种方法不起作用,因为它们似乎都在做同样的事情,即构建一个实体。那么我的问题是,有没有办法在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:我的解决方案 我对匿名类型方法不满意,所以继续创建一个只包含我需要在viewmodel中使用的属性的简单模型。

更改了模型的类型.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。我曾经被一位同事(曾经为微软工作过)警告说以这种方式直接使用实体并不是一个好主意,也许这是他想到的原因之一,我也注意到了一些奇怪的事情。在其他情况下直接使用实体的行为(主要是腐败)。

2 个答案:

答案 0 :(得分: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;

UPDATE:

因为它是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();

答案 1 :(得分:2)

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

我一直注意到LINQ无法使用C#类来选择语句如果通过将查询转换为SQL来访问原始数据源(即ctx /强>

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

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

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

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表达式而不是流畅的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 });

不幸的是,我对这个问题的经验是轶事。我从来没有能够正式确认我对这个问题的根本原因的怀疑;但是我提到的解决方法应该可行,因为我过去曾多次应用它们。

如果有人对根本原因有解释,我会非常有兴趣听到它!