帮助我理解实体框架4缓存延迟加载

时间:2010-04-27 21:07:38

标签: caching entity-framework-4

我在实体框架4.0中遇到了一些意想不到的行为,我希望有人可以帮助我理解这一点。我正在使用northwind数据库来解决这个问题。我也使用默认代码生成器(不是poco或自我跟踪)。我期待随时我查询框架的上下文,如果我还没有获取这些对象,则只进行往返。如果我关闭延迟加载,我会得到这种行为。目前在我的应用程序中,我很简单地打开延迟加载然后将其关闭以便我可以获得所需的行为。这太糟糕了,所以请帮忙。这是一个很好的代码示例,可以演示我的问题。

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

为什么第一段代码会进行无关紧要的往返行程?

2 个答案:

答案 0 :(得分:3)

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

如果对象已经被提取,则从上下文加载对象,如果没有,则从数据库加载,使用ObjectContext.GetObjectByKey()

答案 1 :(得分:2)

第一次“不必要的”旅行是必要的 - 你做了一个新的查询,数据库可能在此期间发生了变化。如果你使用了employees变量(你已经存储了查询的结果),那么就不需要去数据库了。

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

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

您的第二个示例显示了如果您事先知道您想要订单,即急切加载,如何正确执行此操作。请注意您如何不回到上下文再次询问员工,重复使用已加载的员工。