Ho la seguente tabella:
Indicators(A INT, B INT, C INT, D INT, TimeInsertedLocal DateTime) .
E ho l'entità di mappatura EF Core che mappa su questa tabella.
Devo tradurre questa query SQL in una query equivalente Linf ef core.
SELECT A, B, C, D, TimeInsertedLocal
FROM Indicators
WHERE TimeInsertedLocal >=
(
SELECT MAX(I.TimeInsertedLocal)
FROM Indicators AS I
)
e questa è l'entità:
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; }
}
Come scrivere la query LINQ in modo che EF Core generi la stessa query o una query migliore che ottenga lo stesso risultato?
È letteralmente una traduzione uno a uno.
Query SQL
SELECT A, B, C, D , TimeInsertedLocal
FROM Indicators
WHERE TimeInsertedLocal >=
(
SELECT MAX(I.TimeInsertedLocal)
FROM Indicators AS I
)
Query LINQ EF Core:
var indicators = dbContext.Set<Indicator>();
var query = indicators
.Where(i => i.TimeInsertedLocal >= indicators.Max(i2 => (DateTime?)i2.TimeInsertedLocal));
Query SQL generata da EF Core:
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]
)
L'unico dettaglio specifico nella query LINQ è DateTime?
cast all'interno di Max
, altrimenti EF Core proverà ad emulare il comportamento di lancio del metodo LINQ Max
e valuterà il lato client della query.
Naturalmente non ci sono indicatori con un valore di TimeInsertedLocal maggiore del valore più grande di TimeInsertedLocal di tutti gli indicatori.
Tuttavia, è possibile che tu abbia diversi indicatori con un valore uguale al valore più grande di TimeInsertedLocal.
In tal caso, è necessario creare gruppi di indicatori con lo stesso TimeInsertedLocal e prendere il gruppo con il valore più grande.
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();
Se sei certo che TimeInsertedLocal è unico, non è necessario GroupBy, ci sarà solo un indicatore con il TimeInsertedLocal più grande
var indicatorWithLargestTimeInsertedLocal = myDbContext.Indicators
.OrderByDescending(indicator => indicator.TimeInsertedLocal)
.FirstOrDefault();