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

C# 实体框架-具有order by和group by的Linq查询,c#,mysql,linq,entity-framework,C#,Mysql,Linq,Entity Framework,我有Measurement对象,这些对象具有相关属性CreationTime(DateTime)和Reference(String)以及一些其他值 我想为DbContext编写一个高效的linq查询 根据给定的参考对我的测量对象进行分组 根据组中第一个测量值的CreationTime属性或CreationTime属性的平均值对组进行排序 将查询限制为最近的numOfEntries (在后面的步骤中,我计算这些返回组的平均值,但我想这与我的问题无关。) DbContext本身有一个名为Meas

我有
Measurement
对象,这些对象具有相关属性
CreationTime
(DateTime)和
Reference
(String)以及一些其他值

我想为
DbContext
编写一个高效的linq查询

  • 根据给定的
    参考对我的
    测量
    对象进行分组
  • 根据组中第一个测量值的
    CreationTime
    属性或
    CreationTime
    属性的平均值对组进行排序
  • 将查询限制为最近的
    numOfEntries
(在后面的步骤中,我计算这些返回组的平均值,但我想这与我的问题无关。)

DbContext本身有一个名为
Measurements
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();
如何正确选择
测量值的“最近”组

我正在使用实体框架4.4和MySQL数据库(MySQL连接器/NET6.6.4)。这个例子被简化了,我可以更详细地讲,如果必要的话,我可以举个例子


谢谢

尝试在
分组依据
之后移动
订单依据

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();
这是一种方法语法(我觉得更容易阅读),但这可能会做到

更新后的评论

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

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

要按引用属性分组,请执行以下操作:

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”):

要按平均CreationTime对组进行排序,请使用DateTime结构的Ticks属性:

var refGroupsOrderedByAvgCreationTimeQuery = limitedQuery.OrderBy( lq => lq.RecentMeasurements.Average( g => g.CreationTime.Ticks ) );

您可以尝试强制转换GroupBy的结果,并首先将其放入一个可枚举项中,然后处理其余的结果(基于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查询与此类似(取决于您的输入)


我试过了,但得到了一个错误,
DateTime
无法转换为
int
。为了测试,我还尝试了
int
属性,并得到了一个MySqlException,上面写着“字段列表”中的未知列“GroupBy1.K2”谢谢你的建议,但是我得到了一个
NotSupportedException
试图确定g.First()因为
g
不是最终的查询操作。尝试对
CreationTime
属性进行平均失败,因为它不是
int
。我已更新了答案,但在我找到一个理想的答案之前,我无法解决平均日期问题。感谢您的努力。我同时尝试了此操作,还添加了一个“Ticks”属性rty将CreationTime存储为长格式,以便“.Average()”能够正常工作。现在我收到的MySQL异常是“未知列”Distinct1.Reference“in'where子句”(FirstOrDefault)或“未知列”GroupBy1.K2“in'field list”(Average)。MySQL连接器错误是否可能是导致这种情况的原因?(我应该提到,真正的查询有点复杂,我不直接查询数据库集,而是使用另一个查询作为源。)而不是计算“CreationTime的平均值”,您是否考虑过从给定点计算时间跨度,然后确定这些时间跨度的平均值,然后根据给定点和平均时间跨度计算结果日期?
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);
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]