Как перевести этот запрос SQL в запрос LINQ в EF Core? - PullRequest
2 голосов
/ 23 апреля 2019

У меня есть следующая таблица:

Indicators(A INT, B INT, C INT, D INT, TimeInsertedLocal DateTime) . 

И у меня есть объект отображения EF Core, который отображается на эту таблицу.

Мне нужно перевести этот SQL-запрос в ядро ​​эквивалентного запроса Linq.

SELECT A, B, C, D, TimeInsertedLocal
FROM Indicators
WHERE TimeInsertedLocal >= 
(   
    SELECT MAX(I.TimeInsertedLocal) 
    FROM Indicators AS I
) 

и это сущность:

public class Indicator
{
    public int A { get; set; }
    public int B { get; set; }
    public int C { get; set; }
    public int D { get; set; }
    public DateTime TimeInsertedLocal { get; set; }
 }

Как написать запрос LINQ, чтобы EF Core генерировал тот же запрос или лучший запрос, который достигает того же результата?

Ответы [ 2 ]

4 голосов
/ 23 апреля 2019

Это буквально перевод один на один.

SQL-запрос

SELECT A, B, C, D , TimeInsertedLocal
FROM Indicators
WHERE TimeInsertedLocal >= 
(   
    SELECT MAX(I.TimeInsertedLocal) 
    FROM Indicators AS I
)

Запрос EF Core LINQ:

var indicators = dbContext.Set<Indicator>();
var query = indicators
    .Where(i => i.TimeInsertedLocal >= indicators.Max(i2 => (DateTime?)i2.TimeInsertedLocal));

EF Core сгенерированный SQL-запрос:

SELECT [i].[A], [i].[B], [i].[C], [i].[D], [i].[TimeInsertedLocal]
FROM [Indicators] AS [i]
WHERE [i].[TimeInsertedLocal] >= (
    SELECT MAX([i2].[TimeInsertedLocal])
    FROM [Indicators] AS [i2]
)

Единственная конкретная деталь в запросе LINQ - это приведение DateTime? внутри Max, в противном случае EF Core попытается эмулировать поведение при броске метода LINQ Max и оценит запрос на стороне клиента .

1 голос
/ 23 апреля 2019

Конечно, нет индикаторов со значением TimeInsertedLocal, которое больше наибольшего значения TimeInsertedLocal из всех индикаторов.

Однако, возможно, у вас есть несколько индикаторов со значением, равным наибольшему значению TimeInsertedLocal.

Если это так, вам нужно создать группы индикаторов с одинаковым TimeInsertedLocal и взять группу с наибольшим значением.

var indicatorsWithLargestTimeInsertedLocal = myDbContext.Indicators
    // make groups of Indicators with same TimeInsertedLocal:
    .GroupBy(indicator => indicator.TimeInsertedLocal)

    // put the group with the largest TimeInsertedLocal first:
    .OrderByDescending(group => group.Key)

    // The first group of indicators, is the group with the largest value of TimeInsertedLocal
    .FirstOrDefault();

Если вы уверены, что TimeInsertedLocal уникален, вам не нужно использовать GroupBy, будет только один индикатор с наибольшим TimeInsertedLocal

var indicatorWithLargestTimeInsertedLocal = myDbContext.Indicators
    .OrderByDescending(indicator => indicator.TimeInsertedLocal)
    .FirstOrDefault();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...