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

时间:2011-03-16 01:31:18

标签: c# linq extension-methods linq-to-objects

我有以下Linq查询。 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);

我试图将交易记录上的数字设置为递增数字。 这不起作用,留下数字上的空白。

我在查询后也尝试了以下内容。

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

这甚至没有更新Number值。 我做错了什么,或者有一种更简单的方法,使用简洁的linq扩展方法?

2 个答案:

答案 0 :(得分:1)

问题是您要关闭变量totalTransactions,您必须创建要使用的本地副本。 Check Closing over the loop variable considered harmful有更详细的解释。

这样的事情应该有效:

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);

对于使用foreach循环的第二种方法 - 您实际上是在创建一个新的枚举,其中SelectMany()随后就会丢弃:

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

相反,您必须使用ToList()来创建可以安全修改的集合,强制对集合进行热切评估。

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

答案 1 :(得分:1)

另一种思考方式是你有两个序列:

  1. 交易
  2. “自动递增”索引
  3. 你想得到一个序列,有ids的交易。当我们想要组合两个序列时,我们可以使用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); 
    

    这是你的想法吗?

    Zip组合两个序列,直到它到达其中一个序列的末尾。这就是为什么它可以使用Enumberable.Range获得比我们实际需要的更大范围的数字。