LINQ to SQL和有序结果的运行总计

Ecy*_*yrb 35 c# linq linq-to-objects linq-to-sql

我想在a中显示客户的会计历史记录DataGridView,我希望有一个列显示其余额的运行总计.我这样做的旧方法是获取数据,循环数据,逐行添加行DataGridView并计算当时的运行总数.瘸.我宁愿使用LINQ to SQL,或LINQ如果不能使用LINQ to SQL,来计算运行总数,这样我就可以设置DataGridView.DataSource为我的数据.

这是我正在拍摄的一个超级简化的例子.说我有以下课程.

class Item
{
    public DateTime Date { get; set; }
    public decimal Amount { get; set; }
    public decimal RunningTotal { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我想要一个可以生成如下结果的L2S或LINQ语句:

   Date       Amount  RunningTotal
12-01-2009      5          5
12-02-2009     -5          0
12-02-2009     10         10
12-03-2009      5         15
12-04-2009    -15          0
Run Code Online (Sandbox Code Playgroud)

请注意,可能有多个具有相同日期的项目(12-02-2009).在计算运行总计之前,应按日期对结果进行排序.我猜这意味着我需要两个语句,一个用于获取数据并对其进行排序,另一个用于执行运行总计算.

我希望Aggregate能做到这一点,但它并不像我希望的那样有效.或者也许我只是想不出来.

这个问题似乎跟我想要的一样,但我不知道接受/唯一的答案是如何解决我的问题的.

关于如何解决这个问题的任何想法?

编辑 结合Alex和DOK的答案,这就是我最终得到的结果:

decimal runningTotal = 0;
var results = FetchDataFromDatabase()
    .OrderBy(item => item.Date)
    .Select(item => new Item
    {
        Amount = item.Amount,
        Date = item.Date,
        RunningTotal = runningTotal += item.Amount
    });
Run Code Online (Sandbox Code Playgroud)

Ale*_*ini 39

使用闭包和匿名方法:

List<Item> myList = FetchDataFromDatabase();

decimal currentTotal = 0;
var query = myList
               .OrderBy(i => i.Date)
               .Select(i => 
                           {
                             currentTotal += i.Amount;
                             return new { 
                                            Date = i.Date, 
                                            Amount = i.Amount, 
                                            RunningTotal = currentTotal 
                                        };
                           }
                      );
foreach (var item in query)
{
    //do with item
}
Run Code Online (Sandbox Code Playgroud)

  • 我已经尝试使用Linq to Entities(EF)并获得"带有语句体的lambda表达式无法转换为表达式树"编译错误.这与EF特别是L2O相反吗? (5认同)
  • 我希望我能把你们都标记为答案!你的回答很容易理解,并且符合我的例子。不过,我确实喜欢 DOK 如何在分配期间内联增加 `currentTotal`。 (2认同)
  • 请注意,如果您重复使用查询结果,这最终会出错。[这个问题就是这样的结果。](http://stackoverflow.com/questions/25037055/linq-running-total-1st-value- added-to-itself/25037928#25037928) 你可以通过添加一个来解决这个问题`.ToList()` 到查询的结尾。 (2认同)
  • 这个解决方案将强制在客户端执行(即它必须拉下整个结果集才能得到正确的答案)——如果在 SQL 服务器上完成,这样的事情似乎会更高效。 . (2认同)

DOK*_*DOK 26

怎么样:(信用到这个来源)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        delegate string CreateGroupingDelegate(int i);

        static void Main(string[] args)
        {
            List<int> list = new List<int>() { 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 69, 2007};
            int running_total = 0;

            var result_set =
                from x in list
                select new
                {
                    num = x,
                    running_total = (running_total = running_total + x)
                };

            foreach (var v in result_set)
            {
                Console.WriteLine( "list element: {0}, total so far: {1}",
                    v.num,
                    v.running_total);
            }

            Console.ReadLine();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • `running_total =(running_total = running_total + x)`=>心灵狂欢.我肯定会记得下次这个:) (5认同)
  • 请注意,如果您反复使用查询结果,这最终是错误的。[此问题是由此引起的。](http://stackoverflow.com/questions/25037055/linq-running-total-1st-value-added-to-itself/25037928#25037928)您可以通过添加一个`.ToList()`到查询的末尾。 (2认同)

小智 6

如果还没有回答,我有一个我一直在我的项目中使用的解决方案.这与Oracle分区组非常相似.关键是让运行总计中的where子句与orig列表匹配,然后按日期对其进行分组.

var itemList = GetItemsFromDBYadaYadaYada();

var withRuningTotals = from i in itemList    
                       select i.Date, i.Amount,    
                              Runningtotal = itemList.Where( x=> x.Date == i.Date).
                                                      GroupBy(x=> x.Date).
                                                      Select(DateGroup=> DateGroup.Sum(x=> x.Amount)).Single();
Run Code Online (Sandbox Code Playgroud)