2016-04-06 6 views
1

Я работаю над данными. Я хочу получить Промежуточный итог для каждой категории и Всего.Как группировать по категориям и отображать промежуточные итоги в конце строк каждой категории в C# linq

Я хочу добавить строку промежуточного итога в конце строк каждого из них. Моя проблема заключается в том, что я не получаю промежуточный итог для последней категории. Я не знаю, где я ошибся. Любой, кто может мне помочь.

Требуемая мощность:

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

    } 

ответ

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

Спасибо, человек, которого ты спас мне, это упражнение убило меня. –

+0

, когда я использую этот способ более чем в миллионах записей в базе данных, он просто продолжает загружать его, не останавливается. –

+0

Вы имеете в виду приведенный выше код? Производительность не должна отличаться от вашего исходного кода (это только исправление последней проблемы группы). –

0

Используя данные, указанные в вашем вопросе, я создал следующий код на LINQPad, это тот же самый результат, так что визуально у вас есть правильно вставлять значения в пользовательский интерфейс.

  • создал класс транзакций для обработки данных
  • Applied Groupby использованием CategoryID
  • рассчитали Итого и GrandTotal отдельно
  • Вне LINQPad удалить Dump вызов или создать метод расширения

    void Main() 
    { 
    var transactions = new List<Transaction> 
    { 
        new Transaction {CategoryID = 1, Category = "Food", Orgname = "Spar", Penalties = 10, Interest = 0, Admin = 15.3,TotalAmount = 20.3}, 
        new Transaction {CategoryID = 1, Category = "Food", Orgname = "Spar", Penalties = 0, Interest = 10, Admin = 20,TotalAmount = 30}, 
        new Transaction {CategoryID = 2, Category = "Auto", Orgname = "BMW", Penalties = 0, Interest = 30, Admin = 55,TotalAmount = 85}, 
        new Transaction {CategoryID = 2, Category = "Auto", Orgname = "Toyota", Penalties = 9, Interest = 0, Admin = 14.5,TotalAmount = 23.5}, 
        new Transaction {CategoryID = 2, Category = "Auto", Orgname = "Jaguar", Penalties = 22.8, Interest = 8.2, Admin = 50,TotalAmount = 81}, 
        new Transaction {CategoryID = 3, Category = "Banking", Orgname = "Absa", Penalties = 0, Interest = 40, Admin = 155,TotalAmount = 190} 
    }; 
    
    var result = transactions.GroupBy(x => x.CategoryID) 
          .Select(y => new 
             { 
              Transactions = y.Select(z => z), 
              SubTotalPenalties = y.Sum(z => z.Penalties), 
              SubTotalInterest = y.Sum(z => z.Interest), 
              SubTotalAdmin = y.Sum(z => z.Admin), 
              SubTotalTotalAmount = y.Sum(z => z.TotalAmount), 
             }); 
    
    result.Dump(); 
    
    double grandTotalPenalties = result.Sum(y => y.SubTotalPenalties); 
    double grandTotalInterest = result.Sum(y => y.SubTotalInterest); 
    double grandTotalAdmin = result.Sum(y => y.SubTotalAdmin); 
    double grandTotalAmount = result.Sum(y => y.SubTotalTotalAmount); 
    
    grandTotalPenalties.Dump(); 
    grandTotalInterest.Dump(); 
    grandTotalAdmin.Dump(); 
    grandTotalAmount.Dump(); 
    } 
    
    public class Transaction 
    { 
    public int CategoryID { get; set;} 
    
    public string Category { get; set;} 
    
    public string Orgname { get; set;} 
    
    public double Penalties { get; set;} 
    
    public double Interest { get; set;} 
    
    public double Admin { get; set;} 
    
    public double TotalAmount { get; set;} 
        } 
    
+0

Я читаю существующие данные из базы данных. не таким образом вы показываете мне. –

+0

Те же операции можно использовать в коде памяти, который я вставил, я не был очень ясен из начального вопроса, хотя –

+1

Хорошо. Спасибо, что ответ на ваш ответ связан. –

Смежные вопросы