为什么一种方法可以工作而另一种方法不起作用,因为它们似乎都在做同样的事情,即构建一个实体。那么我的问题是,有没有办法在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。我曾经被一位同事(曾经为微软工作过)警告说以这种方式直接使用实体并不是一个好主意,也许这是他想到的原因之一,我也注意到了一些奇怪的事情。在其他情况下直接使用实体的行为(主要是腐败)。
答案 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;
因为它是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 });
不幸的是,我对这个问题的经验是轶事。我从来没有能够正式确认我对这个问题的根本原因的怀疑;但是我提到的解决方法应该可行,因为我过去曾多次应用它们。
如果有人对根本原因有解释,我会非常有兴趣听到它!