2011-04-05 261 views
9

我对这个问题中缺乏细节表示歉意 - 我需要帮助的第一件事就是知道在哪里寻找更多细节。C#Entity Framework 4导致性能下降的导航属性

我有enity框架4导航性能的问题在提交更改时显然导致性能不佳:

this.ObjectContext.SaveChanges(); 

正在30+秒的时候,导航性能(收益表)中的一个包含约8000行(其是不是很多,所以应该罚款)。

我已经使用了SQL事件探查器,并可以看到EF发出SELECT * FROM收据,它是非常缓慢:

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是空的,并且为了添加到收据,它必须首先加载收集。但这并不能解释为什么它通过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); 
      } 
     } 
    } 

回答

1

因为这是一个插入,它刷新你的对象,通过选择价值背部和重新建的对象。现在让我来回答你的问题,你布局:

  1. 你不应该需要调试,而不是SaveChanges(),你看到的可能就是将没有多大意义反正。

  2. 它实际上并没有在做select * from Receipts。它正在做一个select * from Receipts where WarehouseId = 1。因此,出于某些原因,您反对的是将仓库的所有收据与Id一同提取。

  3. 这可能取决于很多事情,您现在无法进入。但是要开始的一个地方是检查应用程序框和数据库框之间的ping速度。还要检查数据库框中的RAM是否已满。那就是我要开始的地方,这就是你所描述的通常的问题。

调试EF的好工具是EF Profiler。 http://efprof.com这将比SQL事件探查器更有帮助。

+0

+1表示efprof.com - 我没有意识到这一点。 -1的成本,305美元??哇 – 2011-04-05 02:30:27

+0

重申你的观点#2。我试图找到原因 - 这可能是问题所在。我确实发现导航属性没有被正确使用,但是修复这个问题并没有删除select *查询 – 2011-04-05 02:32:22

+0

我发现它通过注释掉它,直到它发挥作用。但我不能从代码中看到为什么EF发出select查询。 – 2011-04-05 03:51:18

1

您的问题与“仓库”实体上的“导航属性”有关。删除此导航属性。关系仍然存在,但在创建收货单位时,它不再查询该仓库的所有收货。我有同样的问题,这解决了我的问题。

+0

您能否详细说明一下?这个问题仍然没有解决(它通过使用直接的sql插入语句来应用“修复”)。我所有的POCO类都是自动生成的,因此它们包含每个FK关系的导航属性。你有一个网页的URL描述删除导航属性? (例如,我怎么才能知道什么收据。仓库是当我没有财产了)。谢谢 – 2011-05-13 22:32:38

0

您是否打开了延迟加载?如果是这样,当您访问相关导航属性时,它将触发对WarehouseDetailsReceipts表的查询。我总是确保关闭延迟加载,这样我就不会无意中触发查询。

相关问题