使用实体框架缓慢加载/更新控件 - 我做错了吗?

时间:2014-08-21 19:59:25

标签: c# vb.net entity-framework data-binding ado.net

我对Entity Framework非常陌生,因此,作为测试,我只是创建了一个SQL Server数据库 - 第一个EF6 Winforms项目(在Visual Studio 2013中)并且没有在Visual中更改任何内容Studio创建了代码,例如Lazy / Optimistic loading等。

现在,我从一个有点大的表中获取该项目的所有数据,例如:以下形式的数据:

Var1  | Start_Date |  End_Date  |  .... Other Columns ....
---------------------------------------------------------
Val1  | 1/1/2014   |  1/2/2014  |  ...
Val1  | 1/2/2014   |  1/3/2014  |  ...
Val1  | 1/5/2014   |  1/6/2014  |  ...
Val1  | 1/7/2014   |  1/8/2014  |  ...
Val1  | 1/9/2014   |  1/10/2014 |  ...
    ....
Val2  | 1/1/2014   |  1/2/2014  |  ...
Val2  | 3/2/2014   |  3/3/2014  |  ...
    ....

所以,我想要的是我的表单上的3 ComboBoxes - 一个用户选择Val1,另一个用ComboBox1.Change更新,以显示所有唯一可用于特定值Val1的开始日期和结束日期。

我用来做这个的代码是:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Using ctx As New MyEntities
            Dim Var1Query = (From rw In ctx.MyTable
                             Order By rw.Val1
                             Select rw.Val1).Distinct.ToList

            cboVal1.DataSource = Var1Query 
    End Using
End Sub

Private Sub cboVal1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboVal1.SelectedIndexChanged
    Using ctx As New MyEntities
         ' Figured to get both dates at once rather than 2 trips to the DB
         Dim Dates = (From rw In ctx.MyTable
                      Where rw.Val1= cboVal1.Text
                      Select New With
                      {
                        .Start_Date = rw.Start_Date,
                        .End_Date = rw.End_Date
                      }).ToList


         Dim Start_Dates As List(Of Date)
         Start_Dates = (From el In Dates
                        Select el.Start_Date).Distinct.ToList

         Dim End_Dates As List(Of Date) = 
         End_Dates = (From el In Dates
                      Select el.End_Date).Distinct.ToList

         cboStartDates.DataSource = Start_Dates
         cboEndDates.DataSource = End_Dates
     End Using
End Sub

现在,这很有效,但是当用户在查询新的开始/结束日期时选择新的Val1时,它会非常缓慢甚至挂起用户界面。< / p>

肯定这不是正确的方法,只是想知道做出类似这样的事情的正确方法。

当前环境:

  • Visual Studio 2013
  • 实体框架6
  • SQL Server 2008

另外,即使提供的源代码是VB,我也同样熟悉VB / C#解决方案。

感谢!!!

1 个答案:

答案 0 :(得分:3)

根据您提供的内容,我发现您的EF代码没有任何问题。现在大多数人使用LINQ扩展方法来完成他们需要的东西,因为它不像直接LINQ那样冗长。我确实相信他们最终会被转换为扩展方法。

LINQ:

From record in dbContext.MyTable Select new {record.Start_Date};

LINQ扩展:

dbContext.MyTable.Select(x => new {x.Start_Date});

看看它们如何更短并传达相同的含义?

您选择您感兴趣的字段也是一个非常好的习惯。它将减少发送到服务器的查询的大小,并且还会减少服务器返回的结果。

您正在使用using语句,以便处理上下文,而不会在未使用时保持连接打开。这很好,但是使用winform应用程序,如果上下文应该在显示的表单的生命周期中存在,那么这是值得商榷的。


EF一般

使用LINQ创建条件时,实际上是正在构建的SQL语句,但尚未执行任何操作。在您可以访问查询结果之前,您需要实现&#34;实现&#34;结果。要执行此操作,您只需访问查询中的元素即可将其发送到服务器以获取结果。您 使用ToList执行此操作。除非您仍在有条件地构建查询,否则应始终执行此操作。

非常重要的一点是,在大多数情况下,懒惰加载并不是一件好事。它非常方便,但它可以创建n + 1个条件,因为您在父级上访问的每个子集合项都会生成一个查询来获取它,所以您将获得性能。这是使用像AutoMapper这样的工具或使用Include语句的地方,可以一次性从服务器获取所有内容。

例如:var orderWithDetails = db.Orders.Include(order => order.LineItems).FirstOrDefault(order => order.Id == 4);将生成一个SQL语句,该语句将选择带有id = 4的顺序,并生成其他sql以选择与其关联的所有LineItem记录。如果您没有这样做并且启用了延迟加载,则可能会生成多个影响性能的子查询。

重要的是要记住,ORM只是让我们更容易访问数据,并且不再需要对系统的其他组件进行性能测试。


编辑:

我觉得这应该包括在内,而@BrunoMonteiro确实指出了这一点。当您选择不同的日期时,您正在使用具体化查询Dates。所以这一切都将发生在客户端而不是SQL Server中。根据从Where子句返回的记录集关联的记录数,可能会出现问题。

您应该看到有多少人被退回并且返回了潜在的最大值。如果它看起来过多,我建议你为它们生成单独的语句并将它们发送到SQL Server来处理。通常,客户端在简化的结果集上处理与服务器相同或更好的处理。