Помещение номера заказа в элементы в запросе linq
У меня есть следующий запрос Linq. TransactionData является IEnumerable.
var totalTransactions = 0;
viewModel.GroupedTransactions = transactionData
.GroupBy(x => new { DocumentId = x.DocumentId ?? "Un Documented" })
.Select(x => new GroupedTransaction
{
DocumentId = x.Key.DocumentId,
Transactions = x.Select(y => new Transaction
{
Amount = y.CommitAmount,
ActivityType = y.ActivityType,
Number = totalTransactions++
})
})
.OrderBy(x => x.DocumentId);
где я пытаюсь установить номер в записи транзакции, чтобы быть увеличенным числом. Это не работает, оставляя пробелы в цифрах.
Я также попробовал следующее после запроса.
foreach (var item in viewModel.GroupedTransactions.SelectMany(x => x.Transactions))
{
item.Number = totalTransactions;
totalTransactions++;
}
Это даже не обновило числовое значение. Что я делаю не так, или есть более простой способ, с аккуратным методом расширения linq?
2 ответа
Проблема в том, что вы закрываете переменную totalTransactions
Вы должны создать локальную копию для использования. Проверьте Закрытие по переменной цикла, считающейся вредной для более подробного объяснения.
Примерно так должно работать:
var totalTransactions = 0;
viewModel.GroupedTransactions = transactionData
.GroupBy(x => new { DocumentId = x.DocumentId ?? "Un Documented" })
.Select(x =>
{
new GroupedTransaction()
{
DocumentId = x.Key.DocumentId,
Transactions = x.Select(y =>
{
var currentTransactionId = totalTransactions;
totalTransactions++;
return new Transaction
{
Amount = y.CommitAmount,
ActivityType = y.ActivityType,
Number = currentTransactionId
}
})
}
})
.OrderBy(x => x.DocumentId);
Для вашего второго подхода с циклом foreach - вы фактически создаете новое перечисление с SelectMany()
что вы потом просто выбросите
foreach (var item in viewModel.GroupedTransactions.SelectMany(x => x.Transactions))
{
item.Number = totalTransactions;
totalTransactions++;
}
Вместо этого вы должны принудительно оценить свою коллекцию, используя ToList()
создать коллекцию, которую вы можете смело изменять.
var transactions = viewModel.GroupedTransactions
.SelectMany(x => x.Transactions)
.ToList();
foreach (var item in transactions)
{
item.Number = totalTransactions;
totalTransactions++;
}
Еще один способ думать об этом, что у вас есть две последовательности:
- операции
- индекс с автоинкрементом
И вы хотите получить одну последовательность транзакций с идентификаторами. Когда мы хотим объединить две последовательности, мы можем использовать Zip
оператор:
viewModel.GroupedTransactions = transactionData
.GroupBy(x => new { DocumentId = x.DocumentId ?? "Un Documented" })
.Zip(Enumerable.Range(0, int.MaxValue), (x, index) => new GroupedTransaction
{
DocumentId = x.Key.DocumentId,
Transactions = x.Select(y => new Transaction
{
Amount = y.CommitAmount,
ActivityType = y.ActivityType,
Number = index
})
})
.OrderBy(x => x.DocumentId);
Это то, что вы имели в виду?
Zip объединяет две последовательности, пока не достигнет конца одной из последовательностей. Вот почему все хорошо, Enumberable.Range, чтобы получить гораздо больший диапазон чисел, чем нам на самом деле нужно.