web-dev-qa-db-ja.com

Entity Framework-Order byおよびGroup Byを使用したLinqクエリ

関連するプロパティMeasurement(DateTime)およびCreationTime(String)およびその他の値を持つReferenceオブジェクトがあります。

DbContextに効率的なlinqクエリを書きたい

  • Measurementオブジェクトを特定のReferenceでグループ化します
  • グループの最初のCreationTimeMeasurementプロパティまたはCreationTimeプロパティの平均のいずれかでグループを順序付けます
  • クエリを最新のnumOfEntriesに制限します

(後のステップで、これらの返されたグループの平均値を計算しますが、それは私の問題には関係ないと思います。)

DbContext自体には、Measurementsholding 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();

Measurementsの「最新の」グループを正しく選択するにはどうすればよいですか?

MySQLデータベース(MySql Connector/Net 6.6.4)でEntity Framework 4.4を使用しています。この例は簡略化されており、必要に応じて詳細に説明したり、例を挙げたりすることができます。

ありがとう!

12
zufallsfund

メソッド構文(読みやすいと思います)ですが、これでうまくいくかもしれません

投稿コメントの更新

.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();
12
NinjaNye

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]
2
user3373870

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();
1
MarcinJuraszek

あなたの要件はいたるところにありますが、これは私の理解に対する解決策です:

参照プロパティでグループ化するには:

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 ) );
0
Moho