Subtilitées avec Entity Framework

Lors de nos développements avec entity Framework nous avons été surpris de ne pas retrouver un comportement spécifique avec le lazy loading et les "include" qui est trés connu pour les développeurs sénior dotnet. Avec EF, certaines personnes ont tendance à oublier qu'utiliser des propriétés de navigation avec le lazy va exécuter une second requête. Ainsi si on parcours une collection ou un liste d'objet, et qu'ensuite on utilise la propriété de navigation, vous obtenez :

  1. Une requête pour récupérer la liste d'objet à parcourir
  2. A chaque itération, pour obtenir l'instance de l'objet présent via la propriété de navigation une second requête sera effectué.

On s'aperçoit alors qu'au lieu d'avoir un parcours en O(n) nous avons un parcours en O(n)*(<nb de propriétés>+le temps pour le reste du traitement). Alors qu'avec une jointure, nous aurions récupérer ces objets avec la premiére requête. C'est nettement plus efficace.

Ainsi en optant pour :

var blogs = context.Blogs.Include(blog => blog.Posts).ToList();

En parcourant les blogs, les posts seront disponibles en ayant effectué qu'une seule requête sur le serveur SQL. Maintenant, la subtilité que nous ignorions dans l'équipe sur EF c'est le fait d'utiliser une clause Select.

Le code devient donc quelque chose comme :

var response = context.Blogs.Include(blog => blog.Posts).Select(elt=> new DTO.Blog

{

Id = elt.Id,

...

})ToList();

Ici l'objet Posts n'étant pas mis dans le select du coup, il sera simplement ignoré. De ce fait, l'include ne sert à rien. Aprés vu que l'on cherche à personnaliser le retour pour optimiser les propriétés à renvoyer c'est une bonne chose. Là ou cela devient déroutant, c'est en utilisant cette syntaxe :

var response = context.Blogs.Include(blog => blog.Posts).Select(elt => elt) ou

var response = (from b in context.Blogs

                          join p in context.Posts

                               on b.Id equals p.BlogId

                          select b);

Ici, la collection des posts n'est pas renvoyés... en fait, c'est voulu et la documentation nous l'indique : https://docs.microsoft.com/en-us/ef/core/querying/related-data, allez voir la section Ignored includes. Bref, des subtilités qui nous font perdre pas mal de temps...

J'espére que l'éclaircissement de ce détail, aidera certains d'entre vous.


Rejoindre la conversation