Help me understand entity framework 4 caching for lazy loading

一曲冷凌霜 提交于 2019-12-08 02:13:32

问题


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?


回答1:


Your expectation is not correct. Queries always query the DB. Always. That's because LINQ is always converted to SQL.

To load an object from the context if it's already been fetched and from the DB if it hasn't, use ObjectContext.GetObjectByKey().




回答2:


The first 'unnecessary' trip is necessary - you did a new query and the database could have changed in the meantime. If you used the employees variable instead (where you have stored the result of the query) it wouldn't need to make a trip to the database.

The second one is necessary because you are asking it to fetch the Orders for each Employee. With Lazy loading and no Include() it hasn't read the Orders until you ask it to with emp.Orders.Count().

Remember that until you start iterating on a query (or call some method that requires it to iterate) LINQ to EF does nothing. If you save that query in a variable and then call .Count() on it there will be a round trip. If you use that same query and start enumerating it there will be another round trip. If the entities in that query themselves have relationships and lazy loading is on each time you access one there will be yet another round trip.

Your second example shows how to do this right if you know ahead of time that you want the Orders, that's eager loading. Notice how you don't go back to the context to ask it again for the employees, you reuse the one you've already loaded.



来源:https://stackoverflow.com/questions/2725149/help-me-understand-entity-framework-4-caching-for-lazy-loading

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!