简体   繁体   English

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

[英]Entity Framework - Linq query with order by and group by

I have Measurement Objects with the relevant Properties CreationTime (DateTime) and Reference (String) and some other values. 我有Measurement Objects使用相关的Properties CreationTime (DateTime)和Reference (String)以及其他一些值。

I'd like to write an efficient linq query to a DbContext that 我想为DbContext写一个有效的linq查询

  • groups my Measurement objects by a given Reference 按给定的Reference我的Measurement对象进行分组
  • orders the groups by either the CreationTime Property of the first Measurement from the group or the average of the CreationTime properties 由任一订单组CreationTime第一性能Measurement从上述组或上述的平均CreationTime属性
  • limits the query to the most recent numOfEntries 将查询限制为最新的numOfEntries

(In a later step i calculate averaged values over these returned groups, but i guess that's not relevant for my problem.) (在后面的步骤中,我计算这些返回组的平均值,但我猜这与我的问题无关。)

The DbContext itself has a DbSet<Measurement> called Measurements holding all Measurement objects. DbContext本身有一个DbSet<Measurement>称为Measurements所有Measurement对象。

I came up with the following query, that results in a List of groups that is ordered correctly but is missing some groups in between. 我提出了以下查询,这会产生一个正确排序但缺少某些组的组列表。

var groupByReference = (from m in context.Measurements
                          orderby m.CreationTime
                          group m by new { m.Reference } into g
                          select g).Take(numOfEntries).ToList();

How do I select the "most recent" groups of Measurement s correctly? 如何正确选择“最新” Measurement组?

I'm using Entity Framework 4.4 with a MySQL Database (MySql Connector/Net 6.6.4). 我正在使用Entity Framework 4.4和MySQL数据库(MySql Connector / Net 6.6.4)。 This example is simplified, i can go into more detail and/or give an example if necessary. 这个例子是简化的,我可以进一步详细说明和/或在必要时给出一个例子。

Thanks! 谢谢!

It's method syntax (which I find easier to read) but this might do it 这是方法语法(我觉得更容易阅读),但这可能会这样做

Updated post comment 更新了帖子评论

Use .FirstOrDefault() instead of .First() 使用.FirstOrDefault()而不是.First()

With regard to the dates average, you may have to drop that ordering for the moment as I am unable to get to an IDE at the moment 关于日期平均值,您可能不得不暂时删除该顺序,因为此刻我无法访问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();

You can try to cast the result of GroupBy and Take into an Enumerable first then process the rest (building on the solution provided by NinjaNye 您可以先尝试将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);

Your sql query would look similar (depending on your input) this 您的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]

Try moving the order by after group by : 尝试order by group by后移动order 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();

Your requirements are all over the place, but this is the solution to my understanding of them: 您的要求到处都是,但这是我理解它们的解决方案:

To group by Reference property: 要按引用属性分组:

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

Now you say you want to limit results by "most recent numOfEntries" - I take this to mean you want to limit the returned Measurements... in that case: 现在你说你想用“最近的numOfEntries”来限制结果 - 我认为你想要限制返回的测量值......在这种情况下:

var limitedQuery = from g in refGroupQuery
                   select new
                   {
                       Reference = g.Key,
                       RecentMeasurements = g.OrderByDescending( p => p.CreationTime ).Take( numOfEntries )
                   }

To order groups by first Measurement creation time (note you should order the measurements; if you want the earliest CreationTime value, substitue "g.SomeProperty" with "g.CreationTime"): 要通过第一次测量创建时间来订购组(请注意您应该订购测量;如果您想要最早的CreationTime值,请将“g.SomeProperty”替换为“g.CreationTime”):

var refGroupsOrderedByFirstCreationTimeQuery = limitedQuery.OrderBy( lq => lq.RecentMeasurements.OrderBy( g => g.SomeProperty ).First().CreationTime );

To order groups by average CreationTime, use the Ticks property of the DateTime struct: 要按平均CreationTime对组进行排序,请使用DateTime结构的Ticks属性:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM