如何按类别进行分组,并在C#linq中每个类别的行末尾显示小计

时间:2016-04-06 08:01:13

标签: c# linq datatable

我正在研究数据表。我想获得每个类别的小计总计

我想在每行的行末尾添加小计行。我的问题是我没有得到最后一个类别的小计。我不知道我哪里出错了。 任何能帮助我的人。

必需的输出:

+------------+------------+------------+-----------+----------+-------+-----------+
|CategoryID  |  Category  |  Orgname   | Penalties | Interest | Admin |TotalAmount|
+------------+------------+------------+-----------+----------+-------+-----------+
|   1        | 1-Food     |   Spar     |  $10      |  $0      | $15.3 |  $20.3    |
+-------------------------+------------+-----------+----------+-------+-----------+
|   1        | 1-Food     |Pick n’ Pay |  $0       |  $10     | $20   |  $30      |
+------------+------------+------------+-----------+----------+-------+-----------+
|   Subtotal                           |  $10      |  $10     | $30.3 |  $50.3    |
+-------------------------+------------+-----------+----------+-------+-----------+
|   2        | 2-Auto     |  BMW       |  $0       |  $30     | $55   |  $85      |
|   2        | 2-Auto     | Toyota     |  $9       |  $0      | $14.5 |  $23.5    |
|   2        | 2-Auto     | Jaguar     |  $22.8    |  $8.2    | $50   |  $81      |
+-------------------------+------------+-----------+----------+-------+-----------+
|   Subtotal                           | $31.8     |  $38.2   | $119.5|  $189.5   |
+-------------------------+------------+-----------+----------+-------+-----------+
|   3        | 3-Banking  |  Absa      | $0        |  $40     | $155  |  $190     |
+-------------------------+------------+-----------+----------+-------+-----------+
|   Subtotal                           | $0        |  $40     | $155  |  $190     |
+-------------------------+------------+-----------+----------+-------+-----------+
|   Grand Total                        | $41.8     |  $88.2   | $304.8|  $429,8   |
+-------------------------+------------+-----------+----------+-------+-----------+

我的代码:

var query = (from _transaction in _entities.Transactions
             join _cd in _entities.Organisations on _transaction.Refno equals _cd.Refno
             join _category in _entities.Categorys on _transaction.CategoryID equals _category.CategoryID
             group new { _trans = _transaction, cd = _cd, } 
             by new { _transaction.CategoryID, _transaction.Refno, _cd.Orgname, _category.Description } 
             into _group
             orderby _group.Key.CategoryID
             select new
                { CategoryID = _group.Key.CategoryID,
                  Category = _group.Key.CategoryID + " - " + _group.Key.Description,
                  Refno = _group.Key.Refno,
                  Orgname = _group.Key.Orgname,
                  Penalties = _group.Sum(x => x._trans.Penalties),
                  Interest = _group.Sum(x => x._trans.Interest),
                  Admin = _group.Sum(x => x._trans.Admin),
                  TotalAmount = _group.Sum(x => x._trans.TotalAmount),
                 });
    DataTable dt = new DataTable();
    DataSet ds = new DataSet();
    ds.Tables.Add(query.CopyToDataTable()); ds.Tables[0].TableName = "Table1";
    dt = ds.Tables[0];

    //Get Subtotal
    long _CategoryID = 0; double Admin = 0; double Interest = 0; 
    double Penalties = 0; double TotalAmount = 0; string Title = string.Empty;
    for (int i = 0; i <= dt.Rows.Count - 1; i++)
    {
        if (i > 0)
        {
            if (dt.Rows[i]["Category"].ToString().ToLower() != dt.Rows[i - 1]["Category"].ToString().ToLower())
              {
            dt.Rows.InsertAt(dt.NewRow(), i);
            dt.Rows[i]["CategoryID"] = _CategoryID;
            _CategoryID = 0;
            dt.Rows[i]["Category"] = Title;
            Title = string.Empty;
            dt.Rows[i]["Admin"] = Admin;
            Admin = 0;
            dt.Rows[i]["Interest"] = Interest;
            Interest = 0;
            dt.Rows[i]["Penalties"] = Penalties;
            Penalties = 0;
            dt.Rows[i]["TotalAmount"] = TotalAmount;
            TotalAmount = 0;
            i++;
            }
        }
        Title = "Subtotal";
        _CategoryID = Convert.ToInt64(dt.Rows[i]["CategoryID"]);
        Admin += Convert.ToDouble(dt.Rows[i].IsNull("Admin") ? 0.0 : dt.Rows[i].Field<double>("Admin"));
        Interest += Convert.ToDouble(dt.Rows[i].IsNull("Interest") ? 0.0 : dt.Rows[i].Field<double>("Interest"));
        Penalties += Convert.ToDouble(dt.Rows[i].IsNull("Penalties") ? 0.0 : dt.Rows[i].Field<double>("Penalties"));
        TotalAmount += Convert.ToDouble(dt.Rows[i].IsNull("TotalAmount") ? 0.0 : dt.Rows[i].Field<double>("TotalAmount"));
    }
    // Grand Total
    var subtotal = query.GroupBy(x => x.CategoryID).Select(s => new
    {
        CategoryID = s.Key,
        ISub = s.Sum(x => x.Interest),
        ASub = s.Sum(x => x.Admin),
        PSub = s.Sum(x => x.Penalties),
        TASub = s.Sum(x => x.TotalAmount)
    });
    var GrandTotal = subtotal.Select(s => new
    {
        GI = subtotal.Sum(x => x.ISub),
        GA = subtotal.Sum(x => x.ASub),
        GP = subtotal.Sum(x => x.PSub),
        GTA = subtotal.Sum(x => x.TSub)
    }).Distinct();

    //add grand total row to datatable
    foreach (var a in GrandTotal)
    {
        var dr = dt.NewRow();
        dr["Category"] = "Grand Total";
        dr["Interest"] = a.GI;
        dr["Admin"] = a.GA;
        dr["Penalties"] = a.GP;
        dr["TotalAmount"] = a.GTA;

        dt.Rows.Add(dr);

    }

1 个答案:

答案 0 :(得分:2)

使用单个循环实现分组时,这是一个典型的错误。在这种情况下,最后一组不会被处理,并且在循环之后需要一些代码重复。

这就是我喜欢嵌套循环方法的原因。获取密钥,初始化聚合,处理直到密钥更改并使用组。

将它应用于您的特定情况将是这样的:

//Get Subtotal
for (int i = 0; i < dt.Rows.Count; i++)
{
    // Initialize
    long _CategoryID = Convert.ToInt64(dt.Rows[i]["CategoryID"]);
    double Admin = 0; double Interest = 0;
    double Penalties = 0; double TotalAmount = 0; string Title = string.Empty;
    // Process    
    do
    {
        Admin += Convert.ToDouble(dt.Rows[i].IsNull("Admin") ? 0.0 : dt.Rows[i].Field<double>("Admin"));
        Interest += Convert.ToDouble(dt.Rows[i].IsNull("Interest") ? 0.0 : dt.Rows[i].Field<double>("Interest"));
        Penalties += Convert.ToDouble(dt.Rows[i].IsNull("Penalties") ? 0.0 : dt.Rows[i].Field<double>("Penalties"));
        TotalAmount += Convert.ToDouble(dt.Rows[i].IsNull("TotalAmount") ? 0.0 : dt.Rows[i].Field<double>("TotalAmount"));
        i++;
    }
    while (i < dt.Rows.Count && _CategoryID == Convert.ToInt64(dt.Rows[i]["CategoryID"]));
    // Consume    
    dt.Rows.InsertAt(dt.NewRow(), i);
    dt.Rows[i]["CategoryID"] = _CategoryID;
    dt.Rows[i]["Category"] = "Subtotal";
    dt.Rows[i]["Admin"] = Admin;
    dt.Rows[i]["Interest"] = Interest;
    dt.Rows[i]["Penalties"] = Penalties;
    dt.Rows[i]["TotalAmount"] = TotalAmount;
}