Я прошу прощения за недостаток деталей в этом вопросе - первое, что мне нужно, чтобы помочь, это знать, где искать, чтобы найти больше деталей.
У меня проблема со свойствами навигации enity Framework 4, которые, очевидно, приводят к снижению производительности при фиксации изменений:
this.ObjectContext.SaveChanges();
Требуется более 30 секунд, когда одно из свойств навигации (таблица квитанций) содержит около 8000 строк (что не так много, поэтому должно быть в порядке).
Я использовал профилировщик SQL и вижу, что EF выдает * выбор из квитанций и что он очень медленный:
exec sp_executesql N'SELECT
[Extent1].[Id] AS [Id],
// full field list cut for brevity
FROM [dbo].[Receipts] AS [Extent1]
WHERE [Extent1].[WarehouseId] = @EntityKeyValue1',
N'@EntityKeyValue1 int',@EntityKeyValue1=1
В настоящий момент я даже не вижу , почему необходимо выбрать все строки в этой таблице при вызове ObjectContext.SaveChanges ().
Нужно вставить 1 строку в эту таблицу, но это не объясняет, почему сначала выполняется выбор, и не объясняет, почему этот выбор занимает так много времени (тот же запрос занимает менее 1 секунды в диспетчере запросов. )
Итак, мой вопрос сейчас - я точно не знаю, в чем проблема - это:
- Где / как я могу найти более подробную информацию о проблеме? Я не могу отладить в ObjectContext.SaveChanges (), поэтому я не знаю, что происходит внутри него.
- Почему EF пытается выбрать * из квитанций?
- Почему это так медленно? Точно такой же запрос скопирован + вставлен в менеджер запросов почти мгновенно
РЕДАКТИРОВАТЬ:
Я подтвердил, что это медленный код чека, комментируя вызов этого метода:
private void AddReceipt(PurchaseInvoice invoice,
PurchaseInvoiceLine invoiceLine)
{
if (invoice != null && invoiceLine != null)
{
Product product = invoiceLine.Product;
if (product != null)
{
Receipt receipt = new Receipt{ foo = bar };
WarehouseDetail detail = new WarehouseDetail{ foo = bar };
receipt.WarehouseDetails.Add(detail);
invoice.Receipts.Add(receipt);
}
}
}
Но я все еще не понимаю, почему это заставляет EF выдавать этот запрос * select.
Я полагаю, что это может быть проблема с отложенной загрузкой, вызванная invoice.Receipts.Add(receipt)
. Потому что перед этой строкой invoice.Receipts пуст, и для того, чтобы .Add to Receipts, он должен сначала загрузить коллекцию. НО это не объясняет, почему он выбирается с помощью warehouseId = 1, когда его следует выбирать по invoiceId.
РЕДАКТИРОВАТЬ 2:
Я «исправил» проблему, заменив код EF в этом методе на прямые команды SQL. Это не очень хорошая идея - я не должен разбрасывать SQL, когда у меня есть совершенно хороший ORM. Но сейчас я все еще не понимаю, почему EF выполнял запрос select
private void AddReceipt(PurchaseInvoice invoice,
PurchaseInvoiceLine invoiceLine)
{
if (invoice != null && invoiceLine != null)
{
Product product = invoiceLine.Product;
if (product != null)
{
Receipt receipt = new Receipt{ foo = bar };
WarehouseDetail detail = new WarehouseDetail{ foo = bar };
int id = SqlHelper.AddWarehouseDetail(detail);
receipt.WarehouseDetailId = id;
SqlHelper.AddReceipt(receipt);
}
}
}