Ich habe Measurement
-Objekte mit den relevanten Eigenschaften CreationTime
(DateTime) und Reference
(String) und einigen anderen Werten.
Ich möchte eine effiziente linq-Abfrage an eine DbContext
schreiben
Measurement
-Objekte nach einer gegebenen Reference
CreationTime
-Eigenschaft der ersten Measurement
aus der Gruppe oder den Durchschnitt der CreationTime
-Eigenschaften annumOfEntries
(In einem späteren Schritt berechne ich gemittelte Werte über diese zurückgegebenen Gruppen, aber ich denke, das ist für mein Problem nicht relevant.)
Der DbContext selbst hat einen DbSet<Measurement>
namens Measurements
, der alle Measurement
-Objekte enthält.
Ich habe die folgende Abfrage gefunden, die zu einer Liste von Gruppen führt, die zwar korrekt geordnet ist, jedoch einige Gruppen dazwischen fehlen.
var groupByReference = (from m in context.Measurements
orderby m.CreationTime
group m by new { m.Reference } into g
select g).Take(numOfEntries).ToList();
Wie wähle ich die "neuesten" Gruppen von Measurement
s korrekt aus?
Ich verwende Entity Framework 4.4 mit einer MySQL-Datenbank (MySql Connector/Net 6.6.4). Dieses Beispiel ist vereinfacht, ich kann detaillierter eingehen und/oder, wenn nötig, ein Beispiel geben.
Vielen Dank!
Es ist die Methodensyntax (die ich leichter zu lesen finde), aber das könnte es tun
Aktualisierter Kommentar zum Beitrag
Verwenden Sie .FirstOrDefault()
anstelle von .First()
In Bezug auf den Durchschnittswert der Daten müssen Sie diese Reihenfolge für den Moment fallen lassen, da ich momentan nicht zu einem IDE gelangen kann
var groupByReference = context.Measurements
.GroupBy(m => m.Reference)
.Select(g => new {Creation = g.FirstOrDefault().CreationTime,
// Avg = g.Average(m => m.CreationTime.Ticks),
Items = g })
.OrderBy(x => x.Creation)
// .ThenBy(x => x.Avg)
.Take(numOfEntries)
.ToList();
Sie können versuchen, das Ergebnis von GroupBy und Take in ein Enumerable umzuwandeln und dann den Rest zu verarbeiten (basierend auf der von NinjaNye bereitgestellten Lösung)
var groupByReference = (from m in context.Measurements
.GroupBy(m => m.Reference)
.Take(numOfEntries).AsEnumerable()
.Select(g => new {Creation = g.FirstOrDefault().CreationTime,
Avg = g.Average(m => m.CreationTime.Ticks),
Items = g })
.OrderBy(x => x.Creation)
.ThenBy(x => x.Avg)
.ToList() select m);
Ihre SQL-Abfrage würde ähnlich aussehen (abhängig von Ihrer Eingabe)
SELECT TOP (3) [t1].[Reference] AS [Key]
FROM (
SELECT [t0].[Reference]
FROM [Measurements] AS [t0]
GROUP BY [t0].[Reference]
) AS [t1]
GO
-- Region Parameters
DECLARE @x1 NVarChar(1000) = 'Ref1'
-- EndRegion
SELECT [t0].[CreationTime], [t0].[Id], [t0].[Reference]
FROM [Measurements] AS [t0]
WHERE @x1 = [t0].[Reference]
GO
-- Region Parameters
DECLARE @x1 NVarChar(1000) = 'Ref2'
-- EndRegion
SELECT [t0].[CreationTime], [t0].[Id], [t0].[Reference]
FROM [Measurements] AS [t0]
WHERE @x1 = [t0].[Reference]
Verschieben Sie den order by
nach group by
:
var groupByReference = (from m in context.Measurements
group m by new { m.Reference } into g
order by g.Avg(i => i.CreationTime)
select g).Take(numOfEntries).ToList();
Ihre Anforderungen sind überall, aber dies ist die Lösung für mein Verständnis von ihnen:
So gruppieren Sie nach der Reference-Eigenschaft:
var refGroupQuery = (from m in context.Measurements
group m by m.Reference into refGroup
select refGroup);
Jetzt sagen Sie, Sie möchten die Ergebnisse durch "neueste numOfEntries" begrenzen - ich meine damit, dass Sie die zurückgegebenen Messungen begrenzen wollen ... in diesem Fall:
var limitedQuery = from g in refGroupQuery
select new
{
Reference = g.Key,
RecentMeasurements = g.OrderByDescending( p => p.CreationTime ).Take( numOfEntries )
}
So ordnen Sie Gruppen nach der Erstellungszeit der ersten Messung (Hinweis: Sie sollten die Messungen anordnen; wenn Sie den frühesten CreationTime-Wert erhalten möchten, ersetzen Sie "g.SomeProperty" durch "g.CreationTime"):
var refGroupsOrderedByFirstCreationTimeQuery = limitedQuery.OrderBy( lq => lq.RecentMeasurements.OrderBy( g => g.SomeProperty ).First().CreationTime );
Verwenden Sie zum Sortieren von Gruppen nach durchschnittlicher CreationTime-Eigenschaft die Ticks-Eigenschaft der DateTime-Struktur:
var refGroupsOrderedByAvgCreationTimeQuery = limitedQuery.OrderBy( lq => lq.RecentMeasurements.Average( g => g.CreationTime.Ticks ) );