实体框架 - 减少到数据库的往返

时间:2011-08-16 00:56:41

标签: c# wpf visual-studio-2010 entity-framework entity-framework-4

我正在使用WPF,实体框架和SQLServer编写一个应用程序,所有这些都是非常重要的。我正在查看使用sql profiler对数据库进行的调用,并发现了一些不必要的调用。第一个问题很容易解决,但我已经将它包含在将来阅读此主题的任何人中。假设我有一个包含3个表的表结构,例如Invoice-> InvoiceDetail-> Product

1)当我加载一个Invoice对象时,它将执行一个单独的语句来检索每个InvoiceDetail项。使用Include语句可以很容易地解决这个问题,例如

context.Invoices.Include("InvoiceDetails").Where(i => i.Something == somethingelse);

2)当我删除I​​nvoice时,数据库有一个级联删除,它会自动删除所有InvoiceDetails。但是,EF仍然坚持为内存中的每个InvoiceDetail对象调用一个删除操作。如果发票上有100个项目,那么它将执行101个语句而不是1.这很糟糕。

3)除了在第2点执行的额外声明之外,假设每个InvoiceDetail对象指向一个产品并且我已经将产品加载到内存中(如果我在删除之前显示发票,则会发生这种情况)然后EF对每个产品执行无用的更新语句!!!!事实上,这个更新声明是无用的,因为如果其他人同时改变了产品的某些内容,那么这段代码将改变数据!如果我正在记录更改,那么我们会得到无用的日志条目。我怀疑它是这样做的,因为Product会有一个InvoiceDetails集合,它已删除了一些项目,但产品本身没有改变,为什么要更新?

感谢阅读 干杯, 迈克尔

3 个答案:

答案 0 :(得分:2)

  1. 最初的行为称为延迟加载。您已经用急切加载替换它,这是解决此问题的确切方法。
  2. 对于实体框架,这是唯一正确的行为,因为EF不支持任何批量修改。必须使用自己的语句和数据库往返删除每条记录。一旦你将实体加载到内存,你只需要逐个删除它们,否则你将在任何数据库调用完成之前得到异常(=数据库级联删除将无法帮助你)。唯一的解决方法是删除自定义存储过程,并在运行存储过程后处置当前上下文,因为其内部状态与数据库不一致。
  3. 这很有趣。它需要更多的调查,但它可以简单地设计EF中的缺陷/错误,你很可能不会避免它(除非你使用如2.中所述的存储过程)。如果您想避免覆盖Product中的更改,则必须参与optimistic concurrency。在这种情况下,您的更改不会被覆盖,但删除操作会因OptimisticConcurrencyException而失败。我将在稍后检查此行为,并告诉您我是否能够重现它并找到任何解决方法。

答案 1 :(得分:0)

要删除级联删除(并且可能依赖SQL Server进行删除),请参阅此处的方法:http://geekswithblogs.net/danemorgridge/archive/2010/12/17/ef4-cpt5-code-first-remove-cascading-deletes.aspx

答案 2 :(得分:0)

我一直在使用它作为一种解决方案,让SQL Server在没有EF命中的情况下处理级联删除。

  Public Sub DeleteCheckedOutByUser(ByVal username As String)
    Dim cmd As String = String.Format("delete  Maintenance.CheckoutManager where CheckOutTo = '{0}'", username)
    _context.ExecuteStoreCommand(cmd)
  End Sub

很抱歉,这是在VB中,这是我当前的客户端正在使用的。如果您在翻译我所说的内容时遇到任何问题,请告诉我。