在 linq 查询中为商品添加订单号

发布于 2024-10-22 08:36:36 字数 870 浏览 1 评论 0原文

我有以下 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 扩展方法?

I have the following Linq query. transactionData is an 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.
What am I doing wrong, or is there a simpler way, with a neat linq extension method?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

醉梦枕江山 2024-10-29 08:36:36

问题是您正在关闭变量totalTransactions,您必须创建一个本地副本才能使用。 检查关闭循环变量被认为是有害的以获得更详细的解释。

像这样的事情应该有效:

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++;
}

The problem is that you are closing over the variable totalTransactions, you have to create a local copy to use. 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 (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.

var transactions = viewModel.GroupedTransactions
                            .SelectMany(x => x.Transactions)
                            .ToList();
foreach (var item in transactions)
{
     item.Number = totalTransactions;
     totalTransactions++;
}
幼儿园老大 2024-10-29 08:36:36

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

  1. 事务
  2. “自动递增”索引

并且您想要获得一个序列,即带有 id 的事务。当我们想要组合两个序列时,我们可以使用 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 来获取比我们实际需要的更大范围的数字。

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. When we want to combine two sequences, we can use the Zip operator:

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. Thats why it is ok tu Enumberable.Range to get a much larger range of numbers than we actually need.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文