2010-05-27 8 views
6

Dans Entity Framework (en particulier EF 3.5, mais si elle existe dans EF 4, cela me donne une raison de mettre à niveau) est-il possible de charger seulement une partie d'une collection? Je peux aussi aborder cette erreur, donc je suis ouvert aux suggestions. Mes tableaux/entités ressemble à ceci:Lazy Load Un Entity Framework EntityCollection avec des critères

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

J'ai une liste de Person objets qui ont été récupérés par Entity Framework via une procédure stockée. J'ai une vue qui montre seulement un Meal à la fois, donc je veux seulement l'information liée à ce repas. Actuellement, j'ai le code qui ressemble à ceci:

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 

Le problème est que c'est le chargement de toute la collection. Certes, c'est une petite collection, donc le pire des cas, je peux tout charger et ensuite enlever tout sauf celui dont j'ai besoin, mais c'est loin d'être idéal. De plus, je ne suis pas sûr que ce serait possible sans déclencher aucun des événements de modification de la collection puisqu'ils n'auraient pas dû être là en premier lieu.

+0

Est-ce que 'Person' a une relation many-to-many avec' PersonMeal' et 'PersonMeal' a une relation many-to-many avec' Meal' comme indiqué dans votre question? Ou est-ce que 'Person' a plutôt une relation many-to-many avec' Meal', alors que 'PersonMeal' est la table de connexion? Si c'est le cas, il ne devrait pas y avoir d'entité générée pour 'PersonMeal'. J'ai également remarqué un champ 'Value', cependant. Pourriez-vous clarifier un peu votre structure de données? Une capture d'écran de votre EDM pourrait être utile, ainsi que la structure de votre base de données. – Yakimych

+0

@Yakimych Vous avez raison, c'est un M2M entre Personne et Repas avec PersonMeal étant la table/entité de connexion. –

+0

@ Agent_9191 - Ok, dans ce cas, il devrait y avoir juste une table 'PersonEntity', mais aucune entité générée. L'entité 'Person' devrait avoir une collection de' Meals' et l'entité 'Meal' devrait avoir une collection de' People'. Avez-vous généré votre modèle à partir de la base de données ou l'avez-vous créé vous-même dans le concepteur? Et quelle est la propriété 'Value' pour (cela pourrait être la raison pour laquelle EF génère l'entité' PersonMeal')? – Yakimych

Répondre

2

Dans ce cas, au lieu d'utiliser la méthode Load, vous pouvez simplement interroger la base de données pour vos données:

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 

Je suppose que person.PersonMeals est une collection, sinon vous pouvez utiliser FirstOrDefault au lieu de Take.

Dans cette requête, nous sélectionnons essentiellement toutes les entités PersonMeals (avec le Meal) qui ont l'ID de personne comme la personne actuelle dans la boucle et l'ID de repas que vous voulez. Si votre base de données n'a pas de données corrompues (plusieurs lignes avec les mêmes combinaisons PersonID-MealID), il y aura 0 ou 1 résultats, qui seront écrits dans votre propriété PersonMeals.

+0

P.S .: Désolé pour mon VB. – Yakimych

+0

Pas aussi élégant d'une solution que j'espérais, mais cela fonctionne. –

0

La réponse de Yakimych devrait fonctionner, mais le code a eu quelques erreurs.

correcte syntaxe doit être:

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 

J'espère que ça aide.

1

Votre question était assez claire: est-il possible de paresseusement charger seulement une partie d'une collection et la réponse est non! Pas dans EF1 ni dans EF4. Btw, Si le dernier repas est le sujet, commencez à interroger par ceci! Au lieu de récupérer la personne et son repas, récupérez les derniers repas et la personne qui y est attachée.

+0

Juste pour clarifier - EF ne fournit pas une méthode prête à l'emploi pour charger une partie d'une collection. Et le chargement paresseux signifie que la collection 'Meals' n'est pas chargée avec le' Person', mais plutôt quelque temps après le chargement du 'People'. Ceci, vous pouvez clairement réaliser en demandant les «Repas», cependant. Ainsi, je ne dirais pas simplement que ce n'est pas possible. – Yakimych

+0

Pourquoi la réponse est non? Je pense qu'il n'est pas difficile pour l'équipe EF de mettre en œuvre quelque chose pour résoudre ce problème. –

Questions connexes