简体   繁体   English

在linq查询中的项目上添加订单号

[英]Putting an order number on items in a linq query

I have the following Linq query. 我有以下Linq查询。 transactionData is an IEnumerable. transactionData是一个IEnumerable。

var totalTransactions = 0;
viewModel.GroupedTransactions = transactionData
    .GroupBy(x => new { DocumentId = x.DocumentId ?? "Un Documented" })
    .Select(x => new GroupedTransaction
    {
        DocumentId = x.Key.DocumentId,
        Transactions = x.Select(y => new Transaction
        {
            Amount = y.CommitAmount,
            ActivityType = y.ActivityType,
            Number = totalTransactions++
        })
    })
    .OrderBy(x => x.DocumentId);

where I'm trying to set the Number on the Transaction record to be an incremented number. 我试图将交易记录上的数字设置为递增的数字。 This doesn't work, leaving gaps in the numbers. 这不起作用,留下数字上的空白。

I also tried the following after the query. 我在查询后也尝试了以下内容。

foreach (var item in viewModel.GroupedTransactions.SelectMany(x => x.Transactions))
{
     item.Number = totalTransactions;
     totalTransactions++;
}

This didn't even update the Number value. 这甚至没有更新Number值。 What am I doing wrong, or is there a simpler way, with a neat linq extension method? 我做错了什么,或者有一个更简单的方法,有一个简洁的linq扩展方法?

The problem is that you are closing over the variable totalTransactions , you have to create a local copy to use. 问题是你要关闭变量totalTransactions ,你必须创建一个本地副本来使用。 Check Closing over the loop variable considered harmful for a more detailed explanation. 检查关闭循环变量,认为有害,以获得更详细的说明。

Something like this should work: 这样的事情应该有效:

var totalTransactions = 0;
viewModel.GroupedTransactions = transactionData
    .GroupBy(x => new { DocumentId = x.DocumentId ?? "Un Documented" })
    .Select(x => 
    {
      new GroupedTransaction()
      {
        DocumentId = x.Key.DocumentId,
        Transactions = x.Select(y => 
        {
          var currentTransactionId = totalTransactions;
          totalTransactions++;

          return new Transaction
          {
            Amount = y.CommitAmount,
            ActivityType = y.ActivityType,
            Number = currentTransactionId 
          }
        })
      }
    })
    .OrderBy(x => x.DocumentId);

For your second approach with the foreach loop - you are actually creating a new enumeration with SelectMany() that you subsequently just throw away: 对于使用foreach循环的第二种方法 - 您实际上是使用SelectMany()创建一个新的枚举,然后您将其丢弃:

foreach (var item in viewModel.GroupedTransactions.SelectMany(x => x.Transactions))
{
     item.Number = totalTransactions;
     totalTransactions++;
}

Instead you have to force eager evaluation of your collection by using ToList() to create a collection you can safely modify. 相反,您必须通过使用ToList()创建可以安全修改的集合来强制对集合进行急切评估。

var transactions = viewModel.GroupedTransactions
                            .SelectMany(x => x.Transactions)
                            .ToList();
foreach (var item in transactions)
{
     item.Number = totalTransactions;
     totalTransactions++;
}

Another way to think about it is that you have two sequences: 另一种思考方式是你有两个序列:

  1. Transactions 交易
  2. "auto incremented" index “自动递增”指数

And you want to get one sequence, transactions with ids. 并且您希望得到一个序列,带有ID的事务。 When we want to combine two sequences, we can use the Zip operator: 当我们想要组合两个序列时,我们可以使用Zip运算符:

viewModel.GroupedTransactions = transactionData     
    .GroupBy(x => new { DocumentId = x.DocumentId ?? "Un Documented" })
    .Zip(Enumerable.Range(0, int.MaxValue), (x, index) => new GroupedTransaction     
    {         
        DocumentId = x.Key.DocumentId,         
        Transactions = x.Select(y => new Transaction         
        {             
            Amount = y.CommitAmount,             
            ActivityType = y.ActivityType,             
            Number = index         
        })     
    })     
    .OrderBy(x => x.DocumentId); 

Is this what you had in mind? 这是你的想法吗?

Zip combines two sequences until it reaches the end of one of the sequences. Zip组合两个序列,直到它到达其中一个序列的末尾。 Thats why it is ok tu Enumberable.Range to get a much larger range of numbers than we actually need. 这就是为什么它可以使用Enumberable.Range获得比我们实际需要的更大范围的数字。

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

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