Eager loading en Entity Framework: mejora drástica del rendimiento en acceso a datos - Code Variables -->
Code Variables Code Variables

Latest news

جاري التحميل ...

Eager loading en Entity Framework: mejora drástica del rendimiento en acceso a datos

Sabemos que el uso descontrolado de la carga diferida o lazy loading puede echar abajo el rendimiento de nuestra aplicación, puesto que se generan peticiones al motor de datos al intentar recuperar entidades relacionadas cuando intentamos acceder a ellas. Sin embargo, no son pocos los casos en los que me encuentro que no se está usando apropiadamente, provocando un rendimiento terrible en el acceso a datos de las aplicaciones.


Imaginemos, por ejemplo, la siguiente estructura de datos, que podríamos describir diciendo que un usuario puede tener un número indeterminado de blogs, y en cada uno de ellos existirán un número indeterminado de posts:
Estructura de datos
E imaginemos ahora el siguiente código, que realiza un recorrido en profundidad de estos datos para mostrar los posts de cada blog de cada uno de los usuarios, generando la salida mostrada justo después:
using (var ctx = new MyDataContext())
{
var query = ctx.Users;
foreach (var person in query)
{
Console.WriteLine("User " + person.Name + ":");
foreach (var blog in person.Blogs)
{
Console.WriteLine(" Blog " + blog.Name + ":");
foreach (var post in blog.Posts)
{
Console.WriteLine(" Post: " + post.Title);
}
}
}
}

Salida por consola

Por defecto, con lazy loading activado, la ejecución de esta pequeña porción de código habría generado seis consultas a la base de datos: 
  1. Obtener todos los usuarios. Se obtienen dos instancias de User.
  2. Obtener todos los blogs del primer usuario (jmaguilar). Se obtienen dos instancias de Blog.
  3. Obtener todos los posts del primer blog de jmaguilar. Se obtienen dos instancias de Post.
  4. Obtener todos los posts del segundo blog de jmaguilar. Se obtienen dos instancias de Post.
  5. Obtener todos los blogs del segundo usuario (johnresig). Se obtiene una instancia de Blog.
  6. Obtener todos los posts del único blog del usuario. Se obtiene una instancia de Post.
Este problema se denomina habitualmente el “efecto SELECT N+1” dado que para recorrer una secuencia de tipo maestro-detalle se realiza una consulta para obtener las entidades principales y después N adicionales para obtener las entidades relacionadas con cada una de ellas. Además, el caso que hemos visto es especialmente grave, puesto que involucra una relación uno a muchos en dos niveles, lo cual puede ser terrible para el rendimiento cuando ataquemos colecciones de datos de cierto volumen.

La solución más frecuente es adelantar la carga de las entidades relacionadas, es decir, utilizar eager loading para traerse la estructura completa en una única consulta.

En una estructura como la que hemos visto pero con dos únicos niveles, sería algo así:
using (var ctx = new MyDataContext())
{
var query = ctx.Users.Include(u => u.Blogs);
foreach (var person in query)
{
// Code omitted
}
}
La cláusula Include() indicará a Entity Framework que cuando realice la consulta a la colección de usuarios debe traerse también la colección de blogs relacionados con cada uno de ellos. Si ejecutamos el ejemplo anterior, podremos comprobar que el número de consultas se ha reducido a cuatro:
  1. Obtener todos los usuarios junto con sus blogs.
  2. Obtener todos los posts del primer blog del usuario.
  3. Obtener todos los posts del segundo blog del usuario jmaguilar.
  4. Obtener todos los posts del blog del usuario johnresig.
Es obvio que la mejora definitiva vendrá haciendo que en la primera consulta se obtengan también las instancias de Post asociados con los blogs. Sin embargo, la forma de hacerlo no es tan obvia ni intuitiva como la anterior. No podemos especificarlo en el Include(), puesto que no es posible referenciar la colección como u.Blogs.Posts, dado que Posts no es una propiedad de la colección Blogs del usuario y fallaría en compilación.

La fórmula a emplear en este caso es la siguiente:
using (var ctx = new MyDataContext())
{
var query = ctx.Users.Include(u => u.Blogs.Select(b => b.Posts));
foreach (var person in query)
{
// Code omitted
}
}
Y de esta forma tan simple estaremos obteniendo la estructura de datos completa realizando una única consulta a la base de datos, con el beneficio de rendimiento que esto conlleva.

Publicado en: Variable not found.

Comments



If you like the content of our blog, we hope to stay in constant communication, just enter your email to subscribe to the blog's express mail to receive new blog updates, and you can send a message by clicking on the button next ...

إتصل بنا

About the site

author Code Variables  Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

Learn more ←

Blog visitors

Blog stats

All Copyrights Reserved

Code Variables

2019