2

I am getting some unexpected behaviour with entity framework 4.0 and I am hoping someone can help me understand this. I am using the northwind database for the purposes of this question. I am also using the default code generator (not poco or self tracking). I am expecting that anytime I query the context for the framework to only make a round trip if I have not already fetched those objects. I do get this behaviour if I turn off lazy loading. Currently in my application I am breifly turning on lazy loading and then turning it back off so I can get the desired behaviour. That pretty much sucks, so please help. Here is a good code example that can demonstrate my problem.

Public Sub ManyRoundTrips()
    context.ContextOptions.LazyLoadingEnabled = True
    Dim employees As List(Of Employee) = context.Employees.Execute(System.Data.Objects.MergeOption.AppendOnly).ToList()

    'makes unnessesary round trip to the database, I just loaded the employees'
    MessageBox.Show(context.Employees.Where(Function(x) x.EmployeeID < 10).ToList().Count)
    context.Orders.Execute(System.Data.Objects.MergeOption.AppendOnly)
    For Each emp As Employee In employees
        'makes unnessesary trip to database every time despite orders being pre loaded.'
        Dim i As Integer = emp.Orders.Count
    Next
End Sub

Public Sub OneRoundTrip()
    context.ContextOptions.LazyLoadingEnabled = True
    Dim employees As List(Of Employee) = context.Employees.Include("Orders").Execute(System.Data.Objects.MergeOption.AppendOnly).ToList()

    MessageBox.Show(employees.Where(Function(x) x.EmployeeID < 10).ToList().Count)

    For Each emp As Employee In employees
        Dim i As Integer = emp.Orders.Count
    Next
End Sub

Why is the first block of code making unnessesary round trips?

4

2 回答 2

3

你的期望是不正确的。查询总是查询数据库。总是。那是因为 LINQ 总是转换为 SQL。

要从上下文中加载一个对象(如果它已经被提取),如果它还没有从数据库中加载,请使用ObjectContext.GetObjectByKey()

于 2010-04-27T21:16:47.417 回答
2

第一次“不必要的”旅行是必要的——你做了一个新的查询,同时数据库可能已经改变了。如果您改为使用 employees 变量(存储查询结果的位置),则无需访问数据库。

第二个是必要的,因为您要求它获取每个员工的订单。在延迟加载且没有 Include() 的情况下,在您使用 emp.Orders.Count() 要求它之前,它不会读取 Orders。

请记住,在您开始对查询进行迭代(或调用一些需要它进行迭代的方法)之前,LINQ to EF 什么都不做。如果您将该查询保存在一个变量中,然后在其上调用 .Count() ,则将进行一次往返。如果您使用相同的查询并开始枚举它,将会有另一次往返。如果该查询中的实体本身具有关系,并且每次访问时都打开延迟加载,则将进行另一次往返。

你的第二个例子展示了如果你提前知道你想要订单,那么如何正确地做到这一点,那就是急切的加载。请注意,您如何不返回上下文再次为员工询问,而是重复使用已加载的上下文。

于 2010-04-29T19:52:42.903 回答