0
votes

Performance de la liste nichée de l'entité cadre

Je lutte avec la performance de base du framework d'entité pendant que j'essaie d'ajouter un élément supplémentaire à une liste imbriquée.

disons comme exemple: J'ai plusieurs projets, le projet contient plusieurs maisons, la maison a plusieurs façades et la façade a plusieurs fenêtres. Si je veux maintenant ajouter une fenêtre supplémentaire à un projet spécifique, maison, façade, je le fais comme ça: xxx

Cela fonctionne bien en ce qui concerne la fonctionnalité. Cependant, la performance reste plus lente et plus lente lorsque la base de données augmente. Existe-t-il un moyen plus performant d'ajouter un élément à une liste imbriquée?

J'ai créé une base de données de test simple avec ces objets futuristes avec 50 Projets, chaque projet dispose de 10 maisons, chaque maison dispose de 10 façades et chaque façade a 10 fenêtres. Il en résulte une taille de la base de données d'environ 10 Mo.

dans le test I Ajouter 1000 fenêtres après l'autre (pas de masse):

La solution mentionnée ci-dessus nécessite une durée totale de 145s.

La solution mentionnée par @David Browne - Microsoft prend environ 54s xxx

update 2

Comme recommandé par @david Browne, j'ai ajouté une fourchette à la fenêtre: xxx

La sauvegarde est exécutée comme celle-ci: xxx

Ce problème est la même chose que plus de fenêtres que j'ai plus longtemps est la plus longue. La Durartion pour 1000 fenêtres est d'environ 53 ans.


3 commentaires

Pouvez-vous s'il vous plaît vérifier comment la requête est formée? Au lieu de Inclure , vous pouvez écrire la requête basée sur Joindre pour chercher la façade et ajouter la fenêtre dans l'objet enfant.


Ce premier premier va retirer le premier projet et toutes les maisons, façades et fenêtres pour cela. Utilisez plutôt une combinaison de et selectmany filtrer puis prenez le premier.


@juharrr tu veux dire comme: Var WindowList = Context.ProjectSet.herwhere (p => P.Id == projecdid). Sélectionner (p => p.houses). Où (h => h.id == facadeID). (f => f.facades). Où (f => f.id == facadeID) .Sélectionner (w => w.windows) .tolist (); .Où (F => F.Id == FafadeID) .SelectMany (W => W.Windows) .tolist ();


3 Réponses :


0
votes

Si vous essayez de Ajouter em> une fenêtre à un projet / maison / façade spécifique, pouvez-vous simplement définir la façadeid sur la fenêtre directement et enregistrer cela? Vraisemblablement, la fenêtre a une propriété facadeid, tout comme une façade a une escieuse et la maison a un projecdid. Si la fenêtre a les identifiants de tous ses parents (inutile), il suffit de définir également la maison et les identifiants de projet.

public async Task SaveWindowAsync(Guid facadeId, WindowEntity windowEntity)
{
    using (ProjectsDbContext context = new ProjectsDbContext())
    {
        var facade = Facades.Single(x => x.Id == facadeId);
        windowEntity.Facade = facade;
        facade.Windows.Add(windowEntity);
        await context.SaveChangesAsync();
    }
}


3 commentaires

Je n'aime pas que l'enfant ait l'identifiant du "parent" directement, ce qui définit donc l'identifiant parent n'était pas une option jusqu'à présent.


Vous pouvez toujours ignorer toute cette navigation, charger directement la façade et ajouter la fenêtre droite à celle-ci. Vous connaissez évidemment la facadeID car vous l'utilisez dans l'exemple de requête. Vous pouvez toujours ignorer la navigation dans le projet et la maison pour y arriver. Voir la réponse mise à jour ci-dessus:


Oui, je connais l'ID de la façade mais la fenêtre ne contient actuellement pas l'identifiant de la façade ou la façade. Seule la façade connaît les fenêtres correspondantes.



0
votes

Vous devez d'abord choisir parmi vos fenêtres DBSet, puis rejoindre les façades puis rejoindre les maisons Votre requête devrait ressembler à ce xxx


6 commentaires

Je n'ai actuellement qu'une "DBST projet de projet" vous ajouteriez un DBST supplémentaire au contexte?


Exactement, il ne devrait pas changer votre structure de base de données, mais dans votre code, vous pouvez ajouter cette entité même sans sélection comme écrit Mel.


Cela signifierait que j'essaye sur chaque objet, un identifiant de l'objet «Parent» jusqu'à présent, je n'ai pas cela.


Vous pouvez l'ajouter que votre performance devrait augmenter. Il ne modifie pas non plus le schéma de la base de données.


Ensuite, je devrais gérer toutes les bases de données qui existent déjà.


Idéalement, vos propriétés de code doivent correspondre à la base de données Schema.i Recommander des tutoriels EntityFrameworkTutorial.net/fcore/... EntityFrameworkTutorial.net/fcore/...



2
votes

Je n'ai actuellement que un «projet DBSET», vous ajouteriez un DBST supplémentaire au contexte?

Si vous n'avez pas déclaré DBSet pour une entité, accédez-y via dbcontext.set () , quelque chose comme: xxx

ceci se traduit par: xxx

et ensuite: xxx

Assumer façade a une clé primaire à colonne. S'il a une clé composée de (projetid, feedide, facadeid), ajoutez-les à ceux du .

Le meilleur moyen de le faire, cependant est de définir la clé étrangère Propriété de fenêtre.facadeid et ne charge pas du tout la façade. Dans EF Core, vous pouvez le faire avec des propriétés de Shadow si vous n'avez pas de propriété de clé étrangère. Par exemple: xxx


10 commentaires

C'est beaucoup plus rapide mais il faut toujours plus de temps lorsqu'il y a plus de fenêtres dans la liste des façades. Est-il possible d'éviter de charger toute la liste de façade?


Ce code chargera une seule façade, puis insérez une fenêtre unique (voir la mise à jour pour répondre). Pourquoi dites-vous "il faut plus de temps quand il y a plus de fenêtres dans la liste des façade"?


J'ai un test d'unité qui ajoute 10 '000 Windows à une façade et chaque fois que chaque fois, la durée de l'appel Addwindowow. La durée totale est d'environ 3000s, le premier appel AddWindow prend environ 0,7 une fois qu'il est affiché, il faut environ 0,2 pour que la durée augmente aussi longtemps que possible. La fenêtre de 10'000 ajoute prend environ 1s. Avec ce code, la façade est chargée avec toutes les fenêtres contenant dans la liste.


Le test utilise-t-il un seul dBContext? Si oui, le traqueur de changement doit suivre tous ces objets.


Que voulez-vous dire exactement? J'appelle 10'000 SaveWindowasync (..) C'est donc toujours une nouvelle instance du contexte du projet DB.


OK je vois. Avez-vous un chargement paresseux activé? Au lieu d'ajouter la fenêtre à la facade.windows Navigation Propriété, il suffit de définir la propriété de la facadeid de la fenêtre. docs.microsoft.com/en-us/ef/core/ Modélisation / immobilier ombre . De cette façon, vous n'avez même pas besoin de charger l'entité de la façade.


Pour autant que je sache que la chargement paresseux n'est pas encore mis en œuvre dans un noyau d'entité cadre ou que je manque quelque chose? Je peux essayer cela, mais la question est qu'il existe déjà beaucoup de bases de données dans lesquelles cette propriété Shadow n'existe pas, je l'espère plus facilement.


Avec EF Core, vous devez avoir une propriété d'ombre ou une propriété de clé étrangère. Et je ne peux pas obtenir le comportement de chargement que vous décrivez à reproduire sans chargement paresseux dans EF Core 2.2 ou 3.0.


Je pense que la propriété Shadow est la voie à suivre. Je ne suis pas conscient que EF Core prend en charge le chargement paresseux sans "Microsoft.entityFrameworkcore.proxies" et je n'utilise pas ce paquet.


SE Ma mise à jour 2 Même avec la clé étrangère, il faut le même temps.