Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy Load An Entity Framework EntityCollection with criteria

In Entity Framework (specifically EF 3.5, but if it exists in EF 4 it gives me a reason to upgrade) is it possible to lazy load only part of a collection? I may be approaching this wrong too, so I'm open to suggestions. My tables/entities look similar to this:

Person            PersonMeal           Meal
------    1---*   ----------   *---1   -----
ID                ID                   ID
...               PersonID             ...
                  MealID
                  Value
                  ...

I have a list of Person objects that have been retrieved through Entity Framework via a stored procedure. I have a view that only shows one Meal at a time, so I only want the information related to that meal. Currently I have code that looks like this:

Function GetPersons() As List(Of Person)
    Dim personList = context.StoredProcedureCall(param1, param2, param3).ToList()
    personList.ForEach(Function(x) LazyLoadProperties(x))
    Return personList
End Function

' Work around function because VB lambdas don't take Sub's
Function LazyLoadProperties(ByVal person As Person) As Object
    If (Not person.PersonMeal.IsLoaded) Then
        person.PersonMeal.Load()
    End If
    Return Nothing
End Function

The issue is this is loading up the entire collection. Granted it's a small collection so worst case scenario I can load it all up and then remove all but the one I need, but that is far from ideal. Plus I'm not sure if it would be possible without triggering any of the events of modifying the collection since they shouldn't have been in there in the first place.

like image 833
Agent_9191 Avatar asked May 27 '10 18:05

Agent_9191


2 Answers

In this case, instead of using the Load method, you can just query the database for your data:

Function GetPersons() As List(Of Person)
    Dim personList = context.StoredProcedureCall(param1, param2, param3).ToList()

    Dim person As Person
    For Each person in personList
        person.PersonMeals = From pm in context.PersonMeals.Include("Meal")
                             Where pm.Person.Id == person.Id And pm.Meal.Id == Meal_ID
                             Take 1
    Next person

    Return personList
End Function

I assume that person.PersonMeals is a collection, otherwise you can use FirstOrDefault instead of Take.

In this query we basically select all the PersonMeals entities (together with the Meal) that have the person ID as the current person in the loop and the meal ID you want. If your DB does not have corrupt data (multiple rows with the same PersonID-MealID combinations), there will be 0 or 1 results, which will be written into your PersonMeals property.

like image 103
Yakimych Avatar answered Nov 11 '22 14:11

Yakimych


Your question was pretty clear : is it possible to lazily load only part of a collection and the answer is no ! Not in EF1 nor in EF4. Btw, If the last meal is the subject, start querying by this ! Instead of retrieving the person and there meal, retrieve the last meals and the person attached to it.

like image 28
VdesmedT Avatar answered Nov 11 '22 13:11

VdesmedT