实体框架 - 具有order by和group by的Linq查询

时间:2013-03-22 13:44:18

标签: c# mysql linq entity-framework

我有Measurement个对象,其中包含相关的属性CreationTime(日期时间)和Reference(字符串)以及其他一些值。

我想向DbContext写一个有效的linq查询

  • 按给定的Measurement
  • Reference个对象进行分组
  • 根据群组中第一个CreationTime的{​​{1}}属性或Measurement属性的平均值
  • 对群组进行排序
  • 将查询限制为最新的CreationTime

(在后面的步骤中,我计算这些返回组的平均值,但我猜这与我的问题无关。)

DbContext本身有一个名为numOfEntries的{​​{1}},其中包含所有DbSet<Measurement>个对象。

我提出了以下查询,这会产生一个正确排序但缺少某些组的列表。

Measurements

如何选择&#34;最近的&#34;正确的Measurement组?

我正在使用Entity Framework 4.4和MySQL数据库(MySql Connector / Net 6.6.4)。这个例子是简化的,我可以进一步详细说明和/或在必要时给出一个例子。

谢谢!

4 个答案:

答案 0 :(得分:11)

这是方法语法(我觉得更容易阅读),但这可能会这样做

更新了帖子评论

使用.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();

答案 1 :(得分:1)

您可以先尝试将GroupBy和Take的结果转换为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 :(得分:0)

尝试在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();

答案 3 :(得分:0)

您的要求到处都是,但这是我理解它们的解决方案:

按参考属性分组:

var refGroupQuery = (from m in context.Measurements
            group m by m.Reference into refGroup
            select refGroup);

现在你说你想用“最近的numOfEntries”限制结果 - 我认为你想要限制返回的测量值......在这种情况下:

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