使用let子句的LINQ查询带有计算值

时间:2017-08-05 23:09:08

标签: entity-framework linq

我正在使用带有Entity Framework的ASP.NET Core 1.1版。

我有一个数据库,其中包含一个用于引擎的表,另一个用于在引擎上运行的测试。我正在尝试获取最后的测试结果并将其与每个引擎记录一起显示。我还想用测试结果进行计算。

我想在我的控制器中执行以下操作,并在视图中显示结果:

var engines = from engine in _context.Engine
              orderby engine.SerialNumber
              let lastTest =
                (from t in _context.Test
                 where t.EngineId == engine.EngineId
                 orderby t.TestDate descending
                 select t.TestValue)
                .FirstOrDefault()
              select new EngineVM
              {
                  EngineId = engine.EngineId,
                  Make = engine.Make,
                  Model = engine.Model,
                  SerialNumber = engine.SerialNumber,
                  Status = CalculateEngineStatus(engine.EngineId, engine.AllowedAmount, lastTest)
              };

我收到以下错误:

SqlException :当EXISTS没有引入子查询时,只能在选择列表中指定一个表达式。

我尝试过不同的方法编写查询,但我没有成功。任何建议都将不胜感激。

2 个答案:

答案 0 :(得分:1)

不确定为什么它失败了 SqlException ,但它看起来像EF核心SQL转换器的问题(我在EF 6中没有这个问题)

然而,以下等效查询有效(通过外连接)

var lastTestQuery = from test in _context.Test
                    group test by test.EngineId into engineTests
                    select (from t in engineTests orderby t.TestDate descending select t).FirstOrDefault();

var engines = from engine in _context.Engine
            orderby engine.SerialNumber
            join lastTest in lastTestQuery on engine.EngineId equals lastTest.EngineId into lastEngineTest
            let lastEngineTestValue = (from t in lastEngineTest select t.TestValue).FirstOrDefault()
            select new EngineVM
            {
                EngineId = engine.EngineId,
                Make = engine.Make,
                Model = engine.Model,
                SerialNumber = engine.SerialNumber,
                Status = CalculateEngineStatus(engine.EngineId, engine.AllowedAmount, lastEngineTestValue)
            };

注意:经过一番研究,使用SQL Server Profiler后,看起来EF Core会将其转换为所有引擎和所有测试的两个SELECT语句。用于EF 6的SQL转换程序执行单个查询,但不是EF Core 的情况,它解决了内存中的问题。您应该重新设计这段代码,并提出一些EF Core更容易消化的内容

答案 1 :(得分:0)

您已经编写了查询。您无法在firstOrDefault之后进行选择,因为它不会返回集合。请执行以下操作:

var engines = from engine in _context.Engine
orderby engine.SerialNumber
let lastTest =
(from t in _context.Test
 where t.EngineId == engine.EngineId
 orderby t.TestDate descending
select t.TestValue)
.FirstOrDefault();


 if(engines != null)
{
 // do your calculation here
}