Я выбрал подход, который имитирует данные, поскольку они могли быть материализованы из базы данных неким ORM, то есть классом, который содержит данные и коллекцию детей.Плюс некоторая «бизнес-логика» для расчета необходимых чисел.Таким образом, вы можете выбрать подход БД, а также подход в памяти.
В Linqpad:
void Main()
{
var data = new[]
{
new Record { Id = 1, ParentId = null, Qty = 1, Cost = 0.0m },
new Record { Id = 2, ParentId = 1, Qty = 2, Cost = 0.0m },
new Record { Id = 3, ParentId = 1, Qty = 3, Cost = 0.0m },
new Record { Id = 4, ParentId = 2, Qty = 4, Cost = 0.0m },
new Record { Id = 5, ParentId = 3, Qty = 5, Cost = 0.0m },
new Record { Id = 6, ParentId = 2, Qty = 6, Cost = 1.7m },
new Record { Id = 7, ParentId = 4, Qty = 7, Cost = 1.8m },
new Record { Id = 8, ParentId = 5, Qty = 8, Cost = 1.9m },
new Record { Id = 9, ParentId = 5, Qty = 9, Cost = 2.0m },
}.ToList();
// Mimic ORM's job:
data.ForEach(d => d.ChildRecords =
data.Where(c => c.ParentId == d.Id).ToList());
data.Select(d => new { d.Id, d.Cost, d.TotalCost } ).Dump();
}
class Record
{
public int Id { get; set; }
public int? ParentId { get; set; }
public int Qty { get; set; }
private decimal _cost = 0m;
public decimal Cost
{
get { return this._cost + this.ChildRecords.Sum(cr => cr.TotalCost); }
set { this._cost = value; }
}
public decimal TotalCost
{
get { return this.Qty * this.Cost; }
}
public ICollection<Record> ChildRecords;
}
Результат:
Id Cost TotalCost
1 619.2 619.2
2 60.6 121.2
3 166 498
4 12.6 50.4
5 33.2 166
6 1.7 10.2
7 1.8 12.6
8 1.9 15.2
9 2 18
Оптимизация может бытьприменить некоторую памятку, т. е. позволить свойству Cost хранить результат своего метода получения в закрытой переменной-члене.