関連するプロパティMeasurement
(DateTime)およびCreationTime
(String)およびその他の値を持つReference
オブジェクトがあります。
DbContext
に効率的なlinqクエリを書きたい
Measurement
オブジェクトを特定のReference
でグループ化しますCreationTime
のMeasurement
プロパティまたはCreationTime
プロパティの平均のいずれかでグループを順序付けますnumOfEntries
に制限します(後のステップで、これらの返されたグループの平均値を計算しますが、それは私の問題には関係ないと思います。)
DbContext自体には、Measurements
holding Measurement
オブジェクトと呼ばれるDbSet<Measurement>
があります。
私は次のクエリを思い付きました。その結果、グループのリストは正しく順序付けられていますが、間にいくつかのグループがありません。
var groupByReference = (from m in context.Measurements
orderby m.CreationTime
group m by new { m.Reference } into g
select g).Take(numOfEntries).ToList();
Measurement
sの「最新の」グループを正しく選択するにはどうすればよいですか?
MySQLデータベース(MySql Connector/Net 6.6.4)でEntity Framework 4.4を使用しています。この例は簡略化されており、必要に応じて詳細に説明したり、例を挙げたりすることができます。
ありがとう!
メソッド構文(読みやすいと思います)ですが、これでうまくいくかもしれません
投稿コメントの更新
.FirstOrDefault()
の代わりに.First()
を使用します
日付の平均に関しては、IDEに到達することができないので、しばらくの間その順序を落とさなければならない場合があります
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();
GroupByの結果をキャストし、最初にEnumerableにテイクしてから、残りを処理することができます(NinjaNyeが提供するソリューションに基づいて構築します)
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);
SQLクエリは(入力に応じて)このようになります。
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]
order by
の後に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();
あなたの要件はいたるところにありますが、これは私の理解に対する解決策です:
参照プロパティでグループ化するには:
var refGroupQuery = (from m in context.Measurements
group m by m.Reference into refGroup
select refGroup);
ここで、「最新のnumOfEntries」で結果を制限する必要があると言います。返されるMeasurementsを制限することを意味します...その場合:
var limitedQuery = from g in refGroupQuery
select new
{
Reference = g.Key,
RecentMeasurements = g.OrderByDescending( p => p.CreationTime ).Take( numOfEntries )
}
グループを最初の測定値作成時間順に並べる(測定値を並べる必要があることに注意してください。最も早いCreationTime値が必要な場合は、「g.SomeProperty」を「g.CreationTime」に置き換えてください):
var refGroupsOrderedByFirstCreationTimeQuery = limitedQuery.OrderBy( lq => lq.RecentMeasurements.OrderBy( g => g.SomeProperty ).First().CreationTime );
グループを平均CreationTimeで並べ替えるには、DateTime構造体のTicksプロパティを使用します。
var refGroupsOrderedByAvgCreationTimeQuery = limitedQuery.OrderBy( lq => lq.RecentMeasurements.Average( g => g.CreationTime.Ticks ) );