Я работаю над приложением в WinForms. Мои данные хранятся на сервере MSSQL (Azure). Часть моего приложения включает в себя некоторые основные функции биллинга. Одна из имеющихся у меня моделей - это счета-фактуры, но я столкнулся с проблемой производительности. Мой первый вопрос: кто виноват? Мой плохо оптимизированный код или базовая структура сущностей. Основная проблема заключается в том, что я показываю список счетов в DataGridView. Для каждого счета, который я перечисляю, мне нужно сделать несколько вызовов DBContext. Это неуместно? По этой причине мне нужно сделать несколько звонков; один, чтобы получить список счетов для отображения (на основе идентификатора клиента FK), а затем для каждой модели счета я вызываю некоторые методы, которые вычисляют такие вещи, как SubTotal, TaxTotal и т. д. Эти функции приведены ниже.
public decimal SubTotal()
{
decimal subtotal = 0;
List<Billing_InvoiceItems> LineItems = db.Billing_InvoiceItems.Where(a => a.InvoiceID == this.id).AsNoTracking().ToList();
{
foreach (var LineItem in LineItems)
subtotal += (LineItem.Cost * LineItem.Quantity);
}
return subtotal;
}
public decimal TaxTotal()
{
decimal taxtotal = 0;
List<Billing_InvoiceItems> LineItems = db.Billing_InvoiceItems.Where(a => a.InvoiceID == this.id).AsNoTracking().ToList();
foreach (var LineItem in LineItems)
{
if (LineItem.Taxable)
{
taxtotal += LineItem.Cost * (decimal) LineItem.TaxPercentage;
}
}
return taxtotal;
}
public decimal Total()
{
return (this.SubTotal() + this.TaxTotal());
}
public decimal TotalDue()
{
return (this.Total() - this.TotalPaid());
}
public decimal TotalPaid()
{
List<Billing_PaymentToInvoice> paymentsToInvoice = db.Billing_PaymentToInvoice.Where(a => a.InvoiceID == this.id).ToList();
decimal totalpaid = 0;
foreach (var Payment in paymentsToInvoice)
{
totalpaid += (decimal)Payment.AmountApplied;
}
return totalpaid;
}
Я поступаю неразумно, когда мне нужно делать несколько SQL-запросов для каждого счета-фактуры, который я перечисляю? Или есть способ оптимизировать эти функции? Я пробовал один подход к кэшированию элементов счета (что позволяет мне вычислять итоги для отображения пользователю). Однако для этого мне потребовалось иметь функцию, которую я, по-видимому, часто вызывала, чтобы поддерживать кеш в актуальном состоянии.
Обновлено: вы увидите .AsNoTracking () там, в запросе LineItems, это была попытка оптимизировать его при поиске в Интернете.
Да, это действительно неэффективно. Вы можете получить все свои счета-фактуры и их отдельные позиции в вызове 1 db: var invoices = db.AsNoTracking().Invoice.Include(i => i.LineItems).Where(i => i.??? == xxx).ToList();. Теперь используйте это в модели памяти для выполнения расчетов и фильтрации. Такие вещи, как кеширование и AsNoTracking (), окажут гораздо меньшее влияние, чем минимизация ваших вызовов БД.
Позиции @SteveGreene хранятся в отдельной таблице, это имеет значение?
Не в правильно настроенной модели EF. У вас должна быть навигационная коллекция позиций под счетом. См., Например, здесь.
@SteveGreene - это проект Data-First, модели, созданные VS Scaffolding.
Затем он должен автоматически добавить коллекцию, если вы установили связь FK в базе данных.





Кеш должен это делать. Вы можете использовать разные модели кеширования, даже избегая полного пересчета сумм. (когда вы добавляете новый элемент, вы можете просто добавить стоимость к кэшированной общей стоимости). btw Существует агрегатная функция SQL SUM, но я не знаю, быстрее ли она, чем ваши вычисления.