Linq с объединением, суммой и группой по C # - PullRequest
1 голос
/ 24 сентября 2019

У меня есть две таблицы, приведенные ниже: Таблица 01: Доходы.

Id  |  Amount |  Date       | UserId
1   |  50000  | 2019-01-10  |   1
1   |  10000  | 2019-01-15  |   1
1   |  15000  | 2019-02-16  |   1
1   |  20000  | 2019-03-01  |   1

Таблица 02: Расходы.

Id  |  Amount |  Date       | UserId
1   |  10000  | 2019-03-24  |   1
1   |   5000  | 2019-03-24  |   1
1   |  30000  | 2019-04-24  |   1
1   |  20000  | 2019-05-24  |   1

Я хочу собрать месячные доходы и расходы вместе.На самом деле, результат, который я хочу, выглядит примерно так (на основе таблиц выше):

Month  |  Income  |  Expenses
   01  |  60000   |     0
   02  |  15000   |     0
   03  |  20000   |   15000
   04  |    0     |   30000
   05  |    0     |   20000

Что я пробовал до сих пор:

var incomes = await _context.Incomes.Where(i => i.Date.Year == year && i.UserId == id && i.IsApproved).ToListAsync();
var expenses = await _context.Expenses.Where(e => e.Date.Year == year && e.UserId == id && e.IsApproved).ToListAsync();

var yearlyIncomes = incomes.GroupBy(
            i => i.Date.Month, 
            i => i.Amount,
            (month, income) => new { Month = month, Income = income.Sum() }).OrderBy(i => i.Month).ToList();

var yearlyExpenses = expenses.GroupBy(
            e => e.Date.Month, 
            e => e.Amount,
            (month, expense) => new { Month = month, Expense = expense.Sum() }).OrderBy(e => e.Month).ToList();

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

Я также пробовал:

var yearlyIncomes = incomes.GroupBy(x => x.Date.Month)
                        .Select(x => new
                        {
                            Month = x.Key,
                            Income = x.Sum(p => p.Amount),
                            Expense = expenses.Where(c => x.Any(p => p.Date.Month == c.Date.Month)).Sum(c => c.Amount)
                        }).ToList();

Есть ли способ получить желаемый результат одним запросом.

Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 24 сентября 2019

попробуйте это, если вы не хотите группировать его по UserId, вы можете сделать это за один linq, но это будет долго

var groupedIncome = incomes
                 .GroupBy(inc => inc.Date.Month) //group it by month
                 .Select(groupedIncomeByMonth => 
                     new { 
                         Month = groupedIncomeByMonth.Key, 
                         Amount = groupedIncomeByMonth
                                      .Sum(monthIncome => monthIncome.Amount), 
                         IsIncome = true}).ToList(); // Marker for Concat/Union All

var groupedExpenses = expenses
                    .GroupBy(exp => exp.Date.Month)
                    .Select(groupedExpenseByMonth => 
                        new { 
                            Month = groupedExpenseByMonth.Key, 
                            Amount = groupedExpenseByMonth
                                         .Sum(monthExpense => monthExpense.Amount), 
                            IsIncome = false }).ToList(); // marker for Concat/Union All

var result = groupedIncome.Concat(groupedExpenses)
                  .GroupBy(x => x.Month)
                  .Select(r => 
                               new { 
                                       Month = r.Key, 
                                       Income = r.Where(p => p.IsIncome).Sum(g => g.Amount), 
                                       Expense = r.Where(p => !p.IsIncome).Sum(g => g.Amount)
                                   }).ToListAsync();
0 голосов
/ 24 сентября 2019

Вы хотите объединить все данные и сгруппировать их перед материализацией, вызвав метод ToListAsync().

var incomes = _context
    .Incomes
    .Where(i => i.Date.Year == year && i.UserId == id && i.IsApproved)
    .Select(i => new { Month = i.Date.Month, Income = i.Amount, Expense = 0 });

var expenses = _context
    .Expenses
    .Where(e => e.Date.Year == year && e.UserId == id && e.IsApproved)
    .Select(e => new { Month = e.Date.Month, Income = 0, Expense = e.Amount });

var summary = await incomes
    .Concat(expenses)
    .GroupBy(s => s.Month)
    .Select(g => new { Month = g.Key, Incomes = g.Sum(x => x.Income), Expenses = g.Sum(x => x.Expense) })
    .ToListAsync();
...