Добавить дополнительное значение из LINQ

#c# #list #entity-framework #linq

#c# #Список #entity-framework #linq

Вопрос:

У меня есть следующий фрагмент кода:

 var checkRegisters = await Database.Client.Context.CheckRegister
            .Where(cr => cr.CheckingAccount == account 
                   amp;amp; cr.CheckDate >= fromDate 
                   amp;amp; cr.CheckDate <= toDate 
                   amp;amp; cr.Void == "N" )
            .GroupBy(cr => cr.CheckNumber, 
                     cr => cr.Amount, (key, g) => 
                                          new { 
                                                CheckNumber = key, 
                                                Amount = g.Sum()
                                              })
            .OrderBy(c => c.CheckNumber)
            .ToListAsync();
  

Я не совсем понимаю, что он делает, кроме того, что возвращает мне список контрольных номеров и сумм. Таблица CheckRegister содержит столбец Payee, как и соответствующий ModelBuilder из EF:

 entity.Property(e => e.Payee).HasColumnType("varchar(255)");
  

Как я могу добавить получателя платежа в список, который мне возвращается?

Ответ №1:

Что делает код:

В вашей базе данных есть таблица, которая содержит CheckRegisters . У каждого CheckRegister есть по крайней мере свойства CheckingAccount , CheckDate , Void CheckNumber и Amount , и, по вашим словам, у него также есть свойство Payee :

Итак, ваш код описан шаг за шагом.

 // Take the complete table of CheckRegisters:
Database.Client.Context.CheckRegister

// from every checkRegister in this table (every row),
// keep only those checkRegisters that have a CheckingAccount value equal to account
// and a CheckDate value betwen fromData and toDate
// and a value for property Void equalt to "N"

.Where(checkRegister => checkRegister.CheckingAccount == account 
                     amp;amp; checkRegister.CheckDate >= fromDate 
                     amp;amp; checkRegister.CheckDate <= toDate 
                     amp;amp; checkRegister.Void == "N" )

// Group all remaining CheckRegisters into groups with same checkNumber
// Each group will have a property Key which has the value of the common CheckNumber
        .GroupBy(cr => cr.CheckNumber,

           // ElementSelector: from every CheckRegister put only the amount in each grouop 
           checkRegister => checkRegister.Amount,

           // ResultSelector: take every key (which we call checkNumber)
           // and all Amounts of all CheckRegisters with this CheckNumber
           // to make one new object:
           (checkNumber, amountsFromCheckRegistersWithThisCheckNumber) => new
           { 
                CheckNumber = key, 

                // To calculate property Amount: sum all amountsFromCheckRegistersWithThisCheckNumber
                Amount = amountsFromCheckRegistersWithThisCheckNumber.Sum(),
           })

// By now you have a sequence of objects, each with two properties:
// CheckNumber: a checkNumber used in the CheckRegisters that were left after the Where
// Amount: the sum of all Amounts of all CheckRegisters that have this CheckNumber

// Finally you do some Ordering, and convert the resulting elements into a list
.OrderBy(groupedItem => groupedItem.CheckNumber)
.ToListAsync();
  

Теперь желаемое изменение: добавьте Payees .

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

 CheckNumber | Payee | ...
    1       |   A
    2       |   B
    1       |   C
    2       |   C    // note: C  is used again
    1       |   D
  

Если я создам группы с одинаковым контрольным номером, вы получите:

 group CheckNumber 1 [1, A], [1,C], [1,D]
group CheckNumber 2 [2, B], [2,C]
  

Таким образом, в каждой группе может быть более одного сотрудника. Если вас это устраивает, просто опустите ElementSelector и выберите Employees в resultSelector

 var result = Database.Client.Context.CheckRegister
.Where(...)
.GroupBy(cr => cr.CheckNumber,

// ResultSelector: take every key (which we call checkNumber)
// and all CheckRegisters with this CheckNumber
// to make one new object:
(checkNumber, checkRegistersWithThisCheckNumber) => new
{ 
    CheckNumber = checkNumber, 

    // for Employees: Select property Employee, and convert them to a List
    Employees = checkRegistersWithThisCheckNumber
                .Select(checkRegister => checkRegister.Employee)
                .ToList(),

    // Amounts: select the Amounts and Sum
    Amount = checkRegistersWithThisCheckNumber
                 .Select(checkRegister => checkRegister.Amount)
                 .Sum(),
    });
  

Комментарии:

1. Намного ближе, и я думаю, что начинаю прозревать. Единственная ошибка — «key» после CheckNumber = key имени key не существует в текущем контексте. Спасибо за хорошо прокомментированный пример. Есть идеи по поводу ключевой ошибки?

2. упс, введите после того, как я изменил идентификаторы на более описывающие имена. Исправлено

Ответ №2:

Я бы добавил его к объекту, который вы создаете в GroupBy. Поэтому измените строку 3, как показано ниже

 .GroupBy(cr => cr.CheckNumber, cr => cr.Amount, cr => cr.Payee, (key, g) => 
                              new { CheckNumber = key, Amount = g.Sum(), Payee = g.Payee})
  

Обратите внимание, что group by разделяла только по номеру и сумме, поэтому, если вы также группируете по получателю платежа, вы должны ожидать, что результирующий список будет длиннее. Это также предполагает, что получатель платежа — это имя столбца в вашей таблице.

Комментарии:

1. Это и решение @Oscar M выдает ту же ошибку: аргументы типа для метода ‘Запрашиваются. GroupBy …..не может быть выведен из использования. Попробуйте явно указать аргументы типа.

2. Является ли cr объектом, возможно, типа CheckRegister? Можете ли вы добавить получателя платежа в поля этого объекта в виде строки, а затем повторить попытку кода?

3. Я думал, что у меня уже было это в последнем фрагменте кода в моем исходном сообщении с: entity.Property(e => e.Payee).HasColumnType("varchar(255)"); это то, что Entity Framework создала из моей базы данных tables….at по крайней мере, я понимаю, как это работает

4. Я должен добавить, что это ядро Entity Framework. Все еще не работает после того, как попробовал множество вариантов для Group By

Ответ №3:

Добавьте новый столбец в группу с помощью:

 var checkRegisters = await Database.Client.Context.CheckRegister
            .Where(cr => cr.CheckingAccount == account amp;amp; cr.CheckDate >= fromDate amp;amp; cr.CheckDate <= toDate amp;amp; cr.Void == "N" )
            .GroupBy(cr => cr.CheckNumber, cr => cr.Amount, e => e.Payee , (key, g, p) => new { CheckNumber = key, Amount = g.Sum(), Payee = p})
            .OrderBy(c => c.CheckNumber).ToListAsync();
  

Комментарии:

1. Это и решение @cyclopeanCity выдает ту же ошибку: аргументы типа для метода ‘Запрашиваются. GroupBy …..не может быть выведен из использования. Попробуйте явно указать аргументы типа.