简体   繁体   English

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

[英]Get max version within a date period query

I am trying to write a LINQ query that gets all the records and groups them by Period ie Sep-18 and then returns the record with the highest Version number within the periods. 我正在尝试编写一个LINQ查询,该查询将获取所有记录并按PeriodSep-18将它们分组,然后返回该周期内具有最高Version号的记录。 For example if I have three periods contained within my periodNames list the output list should return: 例如,如果我的periodNames列表中包含三个句periodNames则输出列表应返回:

  1. Sep-18 Versions: 1, 2, 3 (Returns record with version 3) Sep-18版本:1、2、3(返回版本3的记录)

  2. Oct-18 Versions: 1, 2 (Returns record with version 2) Oct-18版本:1、2(返回版本2的记录)

  3. Nov-18 Versions: 1, 2, 3, 4 (Returns record with version 4) Nov-18版本:1、2、3、4(具有版本4的返回记录)

This is the query I have written so far: 这是我到目前为止编写的查询:

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

How can I adapt this to the above specification? 如何使它适应以上规范? Thanks 谢谢

You can use GroupBy in order to group the statements and Max in order to find the maximum value, eg 您可以使用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();

The code above returns the Period and the maximum version number only. 上面的代码仅返回期间和最大版本号。 If you need the record with the highest version number for each period, you can use this: 如果需要每个时期的版本号最高的记录,则可以使用以下记录:

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

Please note that the code above first uses a call to ToArray to send the GroupBy-query to the database. 请注意,上面的代码首先使用对ToArray的调用将GroupBy查询发送到数据库。 From the returned groups, the row with the highest version number for each period is then retrieved in memory. 从返回的组中,然后在内存中检索每个期间的最高版本号的行。

尝试使用GroupBy,然后使用orderbydescending获取最大版本号:

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

I think you would have known your solution if you would have written a proper requirement 我想如果您编写了适当的要求,您就会知道您的解决方案

You wrote: 你写了:

...groups them by Period ie Sep-18 and then returns the highest Version number within the periods ...按时段将它们分组,即Sep-18,然后返回时段内的最高版本号

Your examples don't return the highest version number but the row with the highest version number , so let's assume that is what you want: 您的示例未返回最高版本号,而是返回最高版本号的 ,因此,我们假设这是您想要的:

From a sequence of Statements, group these statements into groups of statements with equal Period , and return from every group, the statement with the largest VersionNumber . 从报表,集团这些语句与平等的语句组序列Period ,并从各组,最大的语句返回VersionNumber

You haven't defined what you want if two statements within the same Period have the same VersionNumber. 如果同一期间内的两个语句具有相同的VersionNumber,则尚未定义所需的内容。 Let's assume you think that this will not occur, so you don't care which one is returned in that case. 假设您认为这种情况不会发生,那么您不必担心在这种情况下会返回哪一个。

So you have sequence of Statements , where every Statement has a Period and a VersionNumber . 因此,您具有一系列Statements ,其中每个Statement都有一个Period和一个VersionNumber

Officially you haven't defined the class of Period and VersionNumber , the only thing we know about them is that you have some code that can decide whether two Periods are equal, and you have something where you can decide which VersionNumber is larger. 官方还没有定义类的PeriodVersionNumber ,我们知道他们的唯一的事情是,你有一些代码,可以决定两者是否Periods相等,和你有什么事情,你可以决定哪些VersionNumber较大。

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

If Period is similar to a DateTime and VersionNumber is similar to an int, then these comparers are easy, otherwise you'll need to write comparers. 如果PeriodDateTime相似,而VersionNumber与int相似,则这些比较器很简单,否则您将需要编写比较器。

From your requirement the code is simple: 根据您的要求,代码很简单:

  • Take all input statements 接受所有输入语句
  • Make groups of statements with equal Period 使各组语句的周期相等
  • From every group of statements with this Period keep only the one with the highest VersionNumber 在每个具有此期间的语句组中,仅保留具有最高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); 

Once again: if default comparers can be used to decide when two Periods are equal and which VersionNumber is larger, you don't need to add the comparers. 再说一次:如果可以使用默认比较器来确定两个句点何时相等以及哪个VersionNumber较大,则无需添加比较器。

The disadvantage of the SorBy is that the 3rd and 4rd element etc are also sorted, while you only need the first element, which is the one with the largest VersionNumber. SorBy的缺点是第3个元素和第4个元素等也会排序,而您只需要第一个元素,即第一个具有最大VersionNumber的元素。

This can be optimized by using the less commonly used Aggregate : 这可以通过使用较少使用的Aggregate来优化:

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

This will put the first statement as the newestStatement (= until now this was the one with the highest version number). 这将把第一个语句作为newestStatement(=直到现在这是具有最高版本号的语句)。 The 2nd element will be put in nextStatement. 第二个元素将放在nextStatement中。 both statements will be compared, and if nextStatement has a VersionNumber larger than newestStatement, then nextStatement will be considered to be newer, and thus will replace newestStatement. 将比较这两个语句,如果nextStatement的VersionNumber大于newestStatement,则nextStatement将被认为是较新的,因此将替换newestStatement。 The end of the Aggregate will return newestStatement 聚合的结尾将返回newestStatement

You can try with GroupBy and OrderByDescending and then take first one. 您可以尝试使用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();

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

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