获取日期期限查询中的最高版本

时间:2018-11-27 09:42:23

标签: c# linq

我正在尝试编写一个LINQ查询,该查询将获取所有记录并按PeriodSep-18进行分组,然后返回周期内编号为Version最高的记录。例如,如果我的periodNames列表中包含三个句点,则输出列表应返回:

  1. Sep-18 版本:1、2、3(返回版本3的记录)

  2. Oct-18 版本:1、2(返回带有版本2的记录)

  3. Nov-18 版本:1、2、3、4(返回带有版本4的记录)

这是我到目前为止编写的查询:

var previousStatements = _context.Statements.Where(x => periodNames.Contains(x.Period) &&
                          x.Version == _context.Statement.Max(y => y.Version)).toList();

如何使它适应以上规范?谢谢

4 个答案:

答案 0 :(得分:1)

您可以使用GroupBy来对语句进行分组,使用Max来查找最大值,例如

var previousStatements = _context.Statements.Where(x => periodNames.Contains(x.Period))
   .GroupBy(x => x.Period)
   .Select(x => new { Period = x.Key, MaxVersion = x.Max(y => y.Version))
   .ToList();

上面的代码仅返回“期间”和最大版本号。如果您需要每个时期的版本号最高的记录,则可以使用以下方法:

var previousStatements = (ctx.Items.Where(x => periodNames.Contains(x.Period))
                .GroupBy(x => x.Period)
                .ToArray())
                .Select(x => x.OrderByDescending(y => y.Version).First())
                .ToList();

请注意,上面的代码首先使用对ToArray的调用来将GroupBy查询发送到数据库。从返回的组中,然后在内存中检索每个期间的最高版本号的行。

答案 1 :(得分:1)

尝试使用GroupBy,然后按降序排列以获得最大版本:

_context.GroupBy(f => f.Period).Select(f=>f.OrderByDescending(r=>r.Version).First()).ToList();

答案 2 :(得分:1)

如果您编写了适当的要求,我想您会知道解决方案的

您写道:

  

...按时段将它们分组,即Sep-18,然后返回时段内的最高版本号

您的示例未返回最高版本号,而是具有最高版本号的行,因此,我们假设这是您想要的:

  

从一系列语句中,将这些语句分为Period相等的语句组,然后从每个组中返回VersionNumber最大的语句。

如果同一期间中的两个语句具有相同的VersionNumber,则您尚未定义所需的内容。假设您认为这种情况不会发生,那么您不必担心在这种情况下会返回哪一个。

因此,您有Statements的序列,其中每个Statement都有一个Period和一个VersionNumber

正式地,您尚未定义PeriodVersionNumber的类,我们对它们的唯一了解是,您有一些代码可以确定两个Periods是否相等,然后您可以决定哪个VersionNumber更大。

IEqualityComparer<Period> periodComparer = ...
IComparer<VersionNumber> versionComparer = ...

如果PeriodDateTime类似,而VersionNumber与int类似,则这些比较器很容易,否则您将需要编写比较器。

根据您的要求,代码很简单:

  • 接受所有输入语句
  • 使各组语句的周期相等
  • 在每个具有此期间的语句组中,仅保留具有最高VersionNumber的语句。

    IEnumerable<Statement> statements = ...
    var latestStatementsWithinAPeriod = statements
    .GroupBy(statement => statement.Period,  // group by same value for Period
       (period, statementsWithThisPeriod) =>
       // From every group of statements keep only the one with the highest VersionNumber
       // = order by VersionNumber and take the first
       statementWithThisPeriod
            .OrderByDescending(statement => statement.VersionNumber, 
             versionComparer)
            .FirstOrDefault(),
       periodComparer);
    

再次:如果可以使用默认比较器来确定两个Period何时相等以及哪个VersionNumber较大,则无需添加比较器。

SorBy的缺点是第3个元素和第4个元素等也会排序,而您只需要第一个元素,即具有最大VersionNumber的元素。

这可以通过使用不太常用的Aggregate来优化:

(period, statementsWithThisPeriod) => statementWithThisPeriod.Aggregate(
    (newestStatement, nextStatement) => 
    (versionComparer.Compare(newestStatement.VersionNumber,  nextStatement.VersionNumber) >=0 ) ? 
        newestStatement :
        nextStatement)

这将把第一个语句作为newestStatement(=直到现在这是具有最高版本号的语句)。第二个元素将放在nextStatement中。将比较这两个语句,如果nextStatement的VersionNumber大于newestStatement,则nextStatement将被认为是较新的,因此将替换newestStatement。聚合的结尾将返回newestStatement

答案 3 :(得分:0)

您可以尝试使用GroupBy和OrderByDescending,然后选择第一个。

var statements = _context.Statements 
        .Where(x => periodNames.Contains(x.Period))
        .GroupBy(g => g.Period)
        .Select(s => s.OrderByDescending(o => o.Version)
        .FirstOrDefault()).ToList();