对于这个问题缺乏细节,我深表歉意——我需要帮助的第一件事是知道在哪里寻找更多细节。
我在提交更改时遇到了实体框架 4 导航属性的问题,显然导致性能不佳:
this.ObjectContext.SaveChanges();
当导航属性之一(收据表)包含大约 8000 行(不多,所以应该没问题)时,需要 30 多秒。
我使用了 SQL 探查器,可以看到 EF 发出 select * from Receipts 并且它非常慢:
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 会尝试从 Receipts 中选择 *?
- 为什么这么慢?复制+粘贴到查询管理器中的完全相同的查询几乎是即时的
编辑:
通过注释掉对此方法的调用,我已经确认收据代码很慢:
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 到 Receipts,它必须先加载集合。但是,这并不能解释为什么它是按warehouseId=1 选择的,而它应该按invoiceId 选择。
编辑2:
我已通过用直接 SQL 命令替换此方法中的 EF 代码来“解决”该问题。这不是一个好主意——当我有一个非常好的 ORM 时,我不应该到处乱扔 SQL。但是现在我仍然不明白为什么 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);
}
}
}