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

C# 实体框架-减少到数据库的往返,c#,wpf,visual-studio-2010,entity-framework,entity-framework-4,C#,Wpf,Visual Studio 2010,Entity Framework,Entity Framework 4,我正在使用WPF、实体框架和SQLServer编写一个应用程序,这些都是非常普通的东西。我正在查看使用sql profiler对数据库进行的调用,发现了很多不必要的调用。第一个问题很容易解决,但我已经为以后阅读此文章的人提供了它。假设我有一个包含3个表的表结构,如Invoice->InvoiceDetail->Product 1) 当我加载Invoice对象时,它将执行一个单独的语句来检索每个InvoiceDetail项。使用Include语句很容易解决这个问题,例如 context.Invoi

我正在使用WPF、实体框架和SQLServer编写一个应用程序,这些都是非常普通的东西。我正在查看使用sql profiler对数据库进行的调用,发现了很多不必要的调用。第一个问题很容易解决,但我已经为以后阅读此文章的人提供了它。假设我有一个包含3个表的表结构,如Invoice->InvoiceDetail->Product

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

context.Invoices.Include("InvoiceDetails").Where(i => i.Something == somethingelse);
2) 当我删除发票时,数据库有一个级联删除,它会自动删除所有发票详细信息。但是EF仍然坚持为内存中的每个InvoiceDetail对象调用delete。如果发票上有100个项目,那么它将执行101条语句,而不是1条。这很糟糕

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

谢谢你的阅读 干杯
Michael

要删除级联删除(可能依赖SQL Server执行删除),请参阅此处的方法:

要删除级联删除(可能依赖SQL Server执行删除),请参阅此处的方法:

  • 最初的行为称为延迟加载。您已将其替换为急切加载,这正是此问题的解决方案
  • 对于实体框架,这是唯一正确的行为,因为EF不支持任何批处理修改。每个记录都必须用自己的语句删除,并返回数据库。一旦您将实体加载到内存中,您只需逐个删除它们,否则在执行任何数据库调用之前,您将遇到异常(=数据库级联删除对您没有帮助)。唯一的解决方法是自定义存储过程,用于在运行存储过程后删除和处理当前上下文,因为其内部状态与数据库不一致
  • 这很有趣。这将需要更多的调查,但可能只是EF中的设计缺陷/bug,您很可能无法避免它(除非您使用2中描述的存储过程)。如果您想避免覆盖
    产品中的更改
    ,您必须参与。在这种情况下,您的更改不会被覆盖,但删除将失败,出现
    OptimisticConcurrencyException
    。我将稍后检查此行为,并让您知道我是否能够复制它并找到任何解决方法
  • 最初的行为称为延迟加载。您已将其替换为急切加载,这正是此问题的解决方案
  • 对于实体框架,这是唯一正确的行为,因为EF不支持任何批处理修改。每个记录都必须用自己的语句删除,并返回数据库。一旦您将实体加载到内存中,您只需逐个删除它们,否则在执行任何数据库调用之前,您将遇到异常(=数据库级联删除对您没有帮助)。唯一的解决方法是自定义存储过程,用于在运行存储过程后删除和处理当前上下文,因为其内部状态与数据库不一致
  • 这很有趣。这将需要更多的调查,但可能只是EF中的设计缺陷/bug,您很可能无法避免它(除非您使用2中描述的存储过程)。如果您想避免覆盖
    产品中的更改
    ,您必须参与。在这种情况下,您的更改不会被覆盖,但删除将失败,出现
    OptimisticConcurrencyException
    。我将稍后检查此行为,并让您知道我是否能够复制它并找到任何解决方法

  • 我一直将此作为一种解决方案,让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中,这是我当前的客户端正在使用的。如果您在翻译我说的内容时遇到任何问题,请告诉我。

    我一直将此作为一种解决方案,让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中,这是我当前的客户端正在使用的。如果你在翻译我所说的内容时遇到任何困难,请告诉我。

    哇,我不使用EF,现在我不确定我是否想使用。在绑定到属性的简单属性上,我注意到多次调用。对于任何对SQL有复杂且昂贵调用的属性,我会存储最后一个请求和应答,如果新请求相同,我会返回最后一个应答。对于“仅在绑定到属性的简单属性上,我注意到多次调用”,这可能会在我上面的第1点中介绍。EF的这一部分实际上工作得很好。虽然我确实觉得EF还没有真正实现,而且在未来的某个时候会感觉更完整。它缺少一些真正基本的功能,比如undoWow,我不使用EF,现在我不确定我是否想使用。在绑定到属性的简单属性上,我注意到多次调用。对于任何调用SQL的属性,我会存储最后一个请求和应答,如果新请求相同,我会返回最后一个应答