Entity Framework - Désireux de charge de deux plusieurs-à-plusieurs liens
Désolé pour cet être si long, mais au moins, je crois que j'ai toutes les infos pour être en mesure de comprendre et peut-être aider?
Je voudrais charger des données à partir de ma base de données à l'aide désireux de chargement.
Les données est mis en place dans cinq tableaux, mise en place de deux Niveaux de m:n relations. Il y a donc trois tables contenant des données (commandé dans une sorte de hiérarchie de haut en bas):
CREATE TABLE [dbo].[relations](
[relation_id] [bigint] NOT NULL
)
CREATE TABLE [dbo].[ways](
[way_id] [bigint] NOT NULL
)
CREATE TABLE [dbo].[nodes](
[node_id] [bigint] NOT NULL,
[latitude] [int] NOT NULL,
[longitude] [int] NOT NULL
)
Les deux premiers vraiment se composent seulement de leur propre ID (pour raccorder d'autres données ne sont pas pertinentes ici).
Entre ces trois tableaux de données sont deux m:n tables, avec un tri astuce:
CREATE TABLE [dbo].[relations_ways](
[relation_id] [bigint] NOT NULL,
[way_id] [bigint] NOT NULL,
[sequence_id] [smallint] NOT NULL
)
CREATE TABLE [dbo].[ways_nodes](
[way_id] [bigint] NOT NULL,
[node_id] [bigint] NOT NULL,
[sequence_id] [smallint] NOT NULL
)
C'est, essentiellement, une partie de la structure de données OpenStreetMap. Je laisse Entity Framework construire des objets à partir de cette base de données et configurer les classes exactement comme les tableaux sont.
Le m:n les tableaux sont vraiment exister en tant que classe. (Je comprends en EF, vous pouvez construire vos objets m:n relation sans avoir l'explicite entre la classe - devrais-je essayer de changer le modèle d'objet dans cette voie?)
Ce que je veux faire: de Mon point d'entrée est un élément de la relation.
Je pense qu'il serait préférable de d'abord désireux de charge du moyen m:n relation, et puis dans une boucle d'itération sur que et désireux de charge le plus bas. J'essaie de le faire de la manière suivante
IQueryable<relation> query = context.relations;
query = query.Where( ... ); //filters down to exactly one
query = query.Include(r => r.relation_members);
relation rel = query.SingleOrDefault();
Qui se charge de la relation et de tous les 1:n info en un seul voyage à la base de données - ok, bon. Mais j'ai remarqué qu'il ne charge que le 1:n table, non pas au moyen des données de la table "moyens".
Cela ne change PAS si j'ai modifier la ligne comme ceci:
query = query.Include(r => r.relation_members.Select(rm => rm.way));
Donc je ne peux pas obtenir le niveau intermédiaire chargé ici, il me semble?
Ce que je ne peux pas obtenir de travail à tous est de charger le niveau du nœud de données avec impatience. J'ai essayé le suivant:
foreach (relation_member rm in rel.relation_members) {
IQueryable<way_node> query = rm.way.way_nodes.AsQueryable();
query = query.Include(wn => wn.node);
query.Load();
}
Ce n'travail et s'empressent de charges le niveau intermédiaire, et que tous les 1:n info de way_node dans une déclaration pour chaque itération, mais pas les Informations de nœud (latitude/longitude). Si j'ai accès à une de ces valeurs-je déclencher un autre voyage à la base de données à charger un seul nœud de l'objet.
Ce dernier voyage est mortel, car je veux charger 1 rapport -> 300 façons dont chaque voie -> 2000 nœuds. Donc à la fin je suis frapper le serveur 1 + 300 + 300*2000... une chambre pour une amélioration, je pense.
Mais comment? Je ne peux pas obtenir cette dernière déclaration écrite dans une syntaxe valide ET désireux de chargement.
Les centres d'intérêt; est-il un moyen de charger la totalité du graphe d'objets en un seul voyage, à commencer par un rapport?
OriginalL'auteur Ralf | 2014-01-11
Vous devez vous connecter pour publier un commentaire.
Chargement de tout le graphe en un aller-retour serait:
Cependant, puisque vous dites que les
Include
jusqu'à...Select(rm => rm.way)
n'ai pas de travail, il est peu probable que cela fonctionne. (Et si il fonctionne de la performance n'est pas drôle en raison de la complexité de la requête SQL générée et la quantité de données et des entités de cette requête sera de retour.)La première chose que vous devez examiner de plus est pourquoi
.Include(r => r.relation_members.Select(rm => rm.way))
ne fonctionne pas car il semble correct. Est votre modèle et de la cartographie de la base de données correcte?La boucle pour obtenir les nœuds via le chargement explicite devrait ressembler à ceci:
Concernant le chargement impatient de la façon dont l'entité I impossible de le faire fonctionner. Je pense que tous les mappages sont ok, ils sont générés automatiquement à partir de la base de données et je n'ai pas les modifier. Peut-être qu'ils ne sont pas chargés, parce que l'entité se compose uniquement de sa propre ID pas d'autres champs? L'id est connue que lorsque les relations de l'autre côté est chargé, donc il n'y a pas beaucoup de sens de se joindre à une autre table pour un numéro que je connais déjà?! N'a pas vraiment d'importance - toutes les œuvres que j'aimerais qu'il.
Si vous utilisez EF 5 et .NET 4.5 la requête n'est qu'une fois compilé, puis mis en cache par EF automatiquement. Donc EF ne pas avoir à recompiler les requêtes dans la boucle. Pour .NET 4.0 cependant, les requêtes ne sont pas mis en cache. Au sujet de l'entité avec uniquement l'ID de propriété: Bien, ce serait intéressant si EF "pense", il n'est pas nécessaire, car il ne contient pas d'informations supplémentaires. Je ne pense pas que c'est la raison pour laquelle désireux de chargement ne fonctionne pas, mais qui sait... 🙂
OriginalL'auteur Slauma
Include()
pour une raison quelconque devient parfois ignoré quand il y a du tri/regroupement/association impliquée.Dans la plupart des cas, vous pouvez réécrire un include() en tant que
Select()
dans un anonyme, un objet intermédiaire:Avant:
Après:
De cette façon, la requête ne doit jamais lâche Include() de l'information.
OriginalL'auteur springy76