2010-05-27 19 views
6

In Entity Framework (in particolare EF 3.5, ma se esiste in EF 4 mi dà un motivo per eseguire l'aggiornamento) è possibile caricare solo una parte di una raccolta? Forse mi sto avvicinando a questo torto, quindi sono aperto a suggerimenti. I miei tavoli/entità simile al seguente:Lazy Load Entity Framework EntityCollection con i criteri

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

Ho una lista di Person oggetti che sono stati recuperati tramite Entity Framework tramite una stored procedure. Ho una visione che mostra solo uno Meal alla volta, quindi voglio solo le informazioni relative a quel pasto. Attualmente ho un codice simile al seguente:

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 

Il problema è che si sta caricando l'intera raccolta. Certo, è una piccola raccolta, quindi, nel peggiore dei casi, posso caricarlo tutto e quindi rimuovere tutto tranne quello di cui ho bisogno, ma è tutt'altro che ideale. Inoltre, non sono sicuro che sarebbe possibile senza innescare nessuno degli eventi di modifica della raccolta, poiché in primo luogo non avrebbero dovuto esserci.

+0

"Person" ha una relazione molti-a-molti con "PersonMeal" e "PersonMeal" hanno una relazione molti-a-molti con "Pasto" come mostrato nella domanda? Oppure 'Person' ha piuttosto una relazione molti-a-molti con' Pasto', mentre 'PersonMeal' è la tabella di connessione? In tal caso, non dovrebbe esserci un'entità generata per 'PersonMeal'. Ho notato anche un campo 'Valore', tuttavia. Potresti chiarire un po 'la struttura dei tuoi dati? Uno screenshot del tuo EDM potrebbe essere utile, così come la struttura del tuo database. – Yakimych

+0

@Yakimych Hai ragione, è un M2M tra Persona e Pasto mentre PersonMeal è la tabella/entità di connessione. –

+0

@ Agent_9191 - Ok, in tal caso dovrebbe esserci solo una tabella 'PersonEntity', ma nessuna entità generata. L'entità 'Persona' dovrebbe avere una raccolta di' Pasti' e l'entità 'Pasto' dovrebbe avere una collezione di' Persone'. Hai generato il tuo modello dal database o lo hai creato tu stesso nel designer? E a cosa serve la proprietà 'Valore' (potrebbe essere la ragione per cui EF sta generando l'entità' PersonMeal')? – Yakimych

risposta

2

In questo caso, invece di utilizzare il metodo di Load, si può solo interrogare il database per i dati:

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 

presumo che person.PersonMeals è una collezione, in caso contrario è possibile utilizzare al posto di FirstOrDefaultTake.

In questa query abbiamo praticamente selezionare tutti i PersonMeals entità (insieme al Meal) che hanno l'ID persona come la persona corrente nel loop e l'ID pasto che si desidera. Se il tuo DB non ha dati corrotti (più righe con le stesse combinazioni PersonID-MealID), ci saranno 0 o 1 risultati, che saranno scritti nella tua proprietà PersonMeals.

+0

P.S .: Scusa per il mio VB. – Yakimych

+0

Non elegante come una soluzione che speravo, ma funziona. –

0

La risposta di Yakimych dovrebbe funzionare, ma il codice ha avuto alcuni errori.

sintassi corretta dovrebbe essere:

Private Function GetPersons() As List(Of Person) 
    Dim personList As List(Of Person) = Context.StoredProcedureCall(param1, param2, param3).ToList() 
    For Each p In personList 
     Dim pId As Integer = p.Id 
     p.PersonMeals = (From pm As PersonMeal In context.PersonMeals.Include("Meal") 
         Where (pm.Person.Id = pId And pm.Meal.Id = Meal_ID) Take 1).ToList 
    Next 
    Return personList 
End Function 

spero che aiuta.

1

La tua domanda è stata abbastanza chiara: è possibile pigramente caricare solo parte di una raccolta e la risposta è no! Non in EF1 né in EF4. A proposito, se l'ultimo pasto è l'argomento, inizia a fare una ricerca! Invece di recuperare la persona e il pasto, recupera gli ultimi pasti e la persona ad essa collegata.

+0

Giusto per chiarire: EF non fornisce un metodo immediato per caricare una parte di una raccolta. Il caricamento lento significa che la raccolta "Pasti" non viene caricata insieme alla "Persona", ma piuttosto dopo che sono state caricate le "Persone". Ciò si può chiaramente ottenere interrogando i "pasti", comunque. Quindi, non vorrei semplicemente dichiarare che non è possibile. – Yakimych

+0

Perché la risposta è No? Penso che non sia difficile per il team EF implementare qualcosa per risolvere questo problema. –