В EF6 замена
let x = (...).FirstOrDefault()
на
from x in (...).Take(1).DefaultIfEmpty()
обычно генерирует лучший SQL.
Поэтому обычно я бы предложил
var query = (from o in db.Set<Order>()
from lastStatus in o.OrderStatus
.OrderByDescending(s => s.CreatedDate)
.Take(1)
where lastStatus.Id != 1
select new { o.Name, StatusId = lastStatus.Id }
).ToList();
(нет необходимости в DefaultIfEmpty
(левое соединение), поскольку условие where
в любом случае превратит его во внутреннее соединение).
К сожалению, в настоящее время (EF Core 2.1.4) существует проблема перевода, поэтому приведенные выше выводы приводятдля оценки клиента.
Текущий обходной путь - заменить средство доступа к свойству навигации o.OrderStatus
коррелированным подзапросом:
var query = (from o in db.Set<Order>()
from lastStatus in db.Set<OrderStatus>()
.Where(s => o.Id == s.OrderId)
.OrderByDescending(s => s.CreatedDate)
.Take(1)
where lastStatus.Id != 1
select new { o.Name, StatusId = lastStatus.Id }
).ToList();
, который создает следующий SQL для базы данных SqlServer (боковое соединение):
SELECT [o].[Name], [t].[Id] AS [StatusId]
FROM [Orders] AS [o]
CROSS APPLY (
SELECT TOP(1) [s].*
FROM [OrderStatus] AS [s]
WHERE [s].[OrderId] = [o].[Id]
ORDER BY [s].[CreatedDate] DESC
) AS [t]
WHERE [t].[Id] <> 1