Ho il seguente set di record
ID BatchID ClientName CreatedDateTime
----------- -------------- --------------- -----------------------
1 NULL B 2018-02-16 19:07:46.320
2 NULL B 2018-02-16 19:07:46.320
3 NULL B 2018-02-16 19:07:46.597
4 NULL B 2018-02-16 19:07:46.597
5 NULL B 2018-02-16 19:10:10.260
6 NULL B 2018-02-16 19:10:10.260
7 NULL B 2018-02-16 19:21:34.303
8 NULL B 2018-02-16 19:21:34.303
9 NULL B 2018-02-16 19:21:44.780
10 NULL B 2018-02-16 19:21:44.780
11 NULL A 2018-02-16 19:24:35.623
12 NULL A 2018-02-16 19:24:35.623
13 NULL A 2018-02-16 19:24:42.867
14 NULL A 2018-02-16 19:24:42.867
Sto usando LINQ to SQL in EF Core.
Voglio filtrare i record in cui BatchID
è NULL
e quindi ordinare i record filtrati da CreatedDateTime
e quindi raggrupparli per ClientName
e quindi prendere i primi 5 record dal primo gruppo.
In base al record specificato impostato in precedenza, è necessario restituire record con Ids 1,2,3,4,5 per ClientName B
Quindi ecco la mia domanda
var result = await _DBContext.BatchRequests
.Where(x => x.BatchID.HasValue == false)
.OrderBy(x => x.CreatedDateTime)
.GroupBy(x => x.ClientName)
.FirstAsync();
PROBLEMA
1> La query restituisce il client A
2> Come faccio a prendere solo i primi 5 record
Aggiornamento 1
Sql Profiler mostra quanto segue, non raggruppa nemmeno in SQL
SELECT [x].[ID], [x].[BatchID], [x].[ClientName], [x].[CreatedDateTime]
FROM [BatchRequests] AS [x]
WHERE CASE
WHEN [x].[BatchID] IS NULL
THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END <> 0
ORDER BY [x].[ClientName]
Primo, solitamente OrderBy
non ha alcun effetto (viene ignorato) se seguito da GroupBy
nelle implementazioni Queryable
che traducono le query LINQ in SQL.
In secondo luogo, EF Core attualmente non traduce le query GroupBy
in SQL, ma le elabora in memoria (la cosiddetta valutazione del client ), il che le rende altamente inefficienti. ClientName
conto di ciò, è meglio suddividere il lavoro su due query: una per prendere il ClientName
del primo gruppo e la seconda per ottenere il risultato desiderato:
var baseQuery = _DBContext.BatchRequests
.Where(x => x.BatchId == null)
.OrderBy(x => x.CreatedDateTime);
var clientName = await baseQuery
.Select(x => x.ClientName)
.FirstOrDefaultAsync();
var result = await baseQuery
.Where(x => x.ClientName == clientName)
.Take(5)
.ToListAsync();
In realtà puoi combinare le due domande, ma non sono sicuro se sarà più efficiente (potrebbe essere peggio):
var baseQuery = _DBContext.BatchRequests
.Where(x => x.BatchId == null)
.OrderBy(x => x.CreatedDateTime);
var result = await baseQuery
.Where(x => x.ClientName == baseQuery.Select(y => y.ClientName).FirstOrDefault())
.Take(5)
.ToListAsync();
Dovrai proiettare il risultato del gruppo come qualcosa di questo:
result = await _DBContext.BatchRequests
.Where(x => x.BatchID.HasValue == false)
.OrderBy(x => x.CreatedDateTime)
.ThenBy(x => x.ClientName)
.GroupBy(x => x.ClientName)
.Select( x => new { ClientName= x.ClientName,
TopFive = x.Take(5)
})
.FirstAsync();