78 votes

Comment Entity Framework fonctionne-t-il avec les hiérarchies récursives? Include () semble ne pas fonctionner avec

J'ai un objet. Item a une Catégorie.

Catégorie a ID, Nom, Parents et Enfants. Parents et Enfants sont des catégories aussi.

Quand je fais une requête linq to entities pour un Élément spécifique, il ne renvoie pas à la Catégorie, à moins que j'utilise la fonction include("Catégorie") de la méthode. Mais il n'apporte pas la pleine de la catégorie, avec ses parents et des enfants. Je pourrais faire des Include("Catégorie.Parent"), mais cet objet est quelque chose comme un arbre, j'ai une hiérarchie récursive et je ne sais pas où elle se termine.

Comment puis-je faire de l'EF charger complètement la Catégorie, avec les parents et les enfants, et les parents avec leurs parents et des enfants, et ainsi de suite?

Ce n'est pas quelque chose pour l'ensemble de l'application, pour des considérations de performance, il serait nécessaire que pour cette entité spécifique, de la Catégorie.

27voto

Shiraz Bhaiji Points 34901

Au lieu d'utiliser la méthode "Inculde", vous pouvez utiliser "Load".

Vous pouvez ensuite en faire une pour chacun et parcourir tous les enfants qui chargent leurs enfants. Ensuite, faites un pour chacun à travers leurs enfants, et ainsi de suite.

Le nombre de niveaux que vous allez descendre sera codé en dur dans le nombre de boucles que vous avez.

Voici un exemple d'utilisation de load: http://msdn.microsoft.com/en-us/library/bb896249.aspx

14voto

Alex James Points 15939

Si vous voulez absolument l'ensemble de la hiérarchie chargée, alors si c'était moi, je pourrais essayer d'écrire une procédure stockée, dont le travail est de retourner tous les éléments dans une hiérarchie, le retour de celui que vous demandez pour la première (et de ses enfants par la suite).

Et puis, laissez le EF de la relation de correction de s'assurer qu'ils sont tous branchés.

c'est à dire quelque chose comme:

// the GetCategoryAndHierarchyById method is an enum
Category c = ctx.GetCategoryAndHierarchyById(1).ToList().First();

si vous avez écrit votre procédure stockée correctement, se matérialiser tous les éléments dans la hiérarchie (c'est à dire ToList ()), EF relation de correction des coups de pied dans.

Et puis l'élément que vous souhaitez (First()) doit avoir tous ses Enfants chargés et ils doivent avoir leurs enfants chargés etc. Tous peuplé de que un Magasin de Proc appel, donc pas de problèmes MARS.

Espérons que cette aide

Alex

6voto

Brett Ryan Points 4905

Il pourrait être dangereux si vous n'arriver à charger tous les récursive entités, en particulier sur la catégorie, vous pourriez vous retrouver avec plus que vous négocié pour:

Category > Item > OrderLine > Item
                  OrderHeader > OrderLine > Item
         > Item > ...

Tout d'un coup vous avez chargé la plupart de votre base de données, vous pouvez également chargé de lignes de factures, clients, alors que tous leurs autres factures.

Ce que vous devez faire est quelque chose comme ce qui suit:

var qryCategories = from q in ctx.Categories
                    where q.Status == "Open"
                    select q;

foreach (Category cat in qryCategories) {
    if (!cat.Items.IsLoaded)
        cat.Items.Load();
    // This will only load product groups "once" if need be.
    if (!cat.ProductGroupReference.IsLoaded)
        cat.ProductGroupReference.Load();
    foreach (Item item in cat.Items) {
        // product group and items are guaranteed
        // to be loaded if you use them here.
    }
}

Une meilleure solution est cependant à construire votre requête pour générer une classe anonyme avec les résultats de sorte que vous ne devez frapper votre magasin de données une fois.

var qryCategories = from q in ctx.Categories
                    where q.Status == "Open"
                    select new {
                        Category = q,
                        ProductGroup = q.ProductGroup,
                        Items = q.Items
                    };

De cette façon, vous pourriez retourner un résultat du dictionnaire si nécessaire.

Rappelez-vous, votre contextes devrait être que de courte durée possible.

6voto

JoeBrockhaus Points 482

Vous ne voulez pas faire récursive de chargement de la hiérarchie, à moins que vous permettant à un utilisateur de manière itérative forer vers le bas/vers le haut de l'arbre: Chaque niveau de récursivité est un autre voyage à la base de données. De même, vous aurez envie de chargement différé off afin de prévenir d'autres DB voyages que vous êtes traversant la hiérarchie lors du rendu d'une page ou l'envoi de plus d'un webservice.

Au lieu de cela, interroger le Catalogue, et comprennent les éléments. Ainsi, vous obtenez tous les éléments à la fois hiérarchique et aplatie, alors maintenant vous avez juste besoin d'exclure les non-root éléments à la racine, ce qui devrait être assez trivial.

J'ai eu ce problème et a fourni un exemple détaillé de cette solution à l'autre, ici

3voto

Johannes Rudolph Points 19845

Vous devriez plutôt introduire une table de correspondance qui associe chaque catégorie à un parent et à un enfant, au lieu d’ajouter les propriétés parent et enfant à la cargaison elle-même.

Selon la fréquence à laquelle vous avez besoin de ces informations, vous pouvez les consulter à la demande. Via des contraintes uniques dans la base de données, vous pouvez éviter un nombre infini de relations possibles.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X