Como muchos sabréis, sobre todo lo que ya habéis jugado con la primera version de ADO.NET Entity Framework, una de las novedades en la version actual es la carga perezosa de forma implícita o automática. Esta nueva opción de carga viene marcada de forma automática con la plantilla de generacion de código por defecto, clases prescriptivas, por medio de una opción llamada LazyLoadingEnabled tal como podéis observar en el siguiente trozo de código que muestra el constructor por defecto de un contexto de trabajo generado con ADO.NET EF.
1 2 3 4 5 6 7 |
<span class="rem">/// <summary></span> <span class="rem">/// </summary></span> <span class="kwrd">public</span> dbsampleEntities() : <span class="kwrd">base</span>(<span class="str">"name=xx"</span>, <span class="str">"xx"</span>) { <span class="kwrd">this</span>.ContextOptions.LazyLoadingEnabled = <span class="kwrd">true</span>; OnContextCreated(); } |
1 |
|
Aunque esta opción es realmente cómoda, ya que nos libra dentro del ambiente de un contexto de tener que hacer un Load explícito de una propiedad de navegación, si no tenemos cuidado puede resultar un punto negro dentro del rendimiento por un incremento innecesario de consultas a la base de datos. Pongamos un ejemplo típico de una relación uno a muchos como la que se muestra en la siguiente figura.
Ahora, partiendo de este modelo imáginese que se realiza la siguiente operación:
1 2 3 4 5 6 7 |
<span class="kwrd">using</span> (dbsampleEntities context = <span class="kwrd">new</span> dbsampleEntities()) { context.ContextOptions.LazyLoadingEnabled = <span class="kwrd">true</span>; <span class="kwrd">foreach</span>(Detail item <span class="kwrd">in</span> context.Details) Console.WriteLine(item.Master.masterData); } |
1 |
|
Si miramos el número de consultas por medio de cualquier profiler o Intellitrace podremos ver como el número de consultas es N+1 siendo N el número de elementos de tipo Detail contenidos dentro de la base de datos.
Lógicamente, si conocemos que dentro de nuestro negocio necesitamos acceder a esos datos una solución para resolver este problema es realizar una expansión de consultas, indicando a la consulta de detalles que vamos a necesitar acceder también a su navegación con los maestros. Para realizar esta expansión de consultas en ADO.NET EF disponemos desde la primera versión del producto del método Include. El siguiente trozo de código muestra como realizar el mismo proceso que anteriormente con expansión de consultas.
1 2 3 4 5 6 7 8 9 |
<span class="kwrd">using</span> (dbsampleEntities context = <span class="kwrd">new</span> dbsampleEntities()) { context.ContextOptions.LazyLoadingEnabled = <span class="kwrd">true</span>; <span class="kwrd">foreach</span>(Detail item <span class="kwrd">in</span> context.Details.Include(<span class="str">"Master"</span>)) Console.WriteLine(item.Master.masterData); Console.ReadLine(); } |
NOTA: Para todos los que estéis chillando por poner el nombre de la propiedad de navegación, Master, entre comillas, saber que es posible crear un método extensor para superar este problema, pondré un post con esto dentro de poco.
Si revisamos ahora nuestro Intellitrace veremos como el número de las consultas se ha quedado solamente en 1, que consiste en un simple INNER JOIN entre Detail y Master
Saludos
Unai Zorrilla
Tal y como comentaba en el último Tip de rendimiento de EF, aquí , el uso del método de expansión de
en la linea Context.ContextOptions.LazyLoadingEnabled = true;
no debe establecerce la propiedad LazyLoadingEnabled en false para que no traiga las demas tablas?
A ver, lo que comento en este TIP no es como desactivar Lazy Loading implícito o la decisión de usarlo, sino el tener en cuenta cuando tiene sentido utilizarlo y cuando hacer una expansion de consultas en vez de delegar en lazy loading.
Unai
Hola Unai. Una pregunta al respecto pero en sentido contrario. ¿Es posible disponer de LazyLoading implícito usando STEs? Parece que por defecto no está disponible esa opción, y para obtenerlo habría que modificar las plantillas t4. Si es así, tienes alguna pista sobre ello?
Muchas gracias.
Revisa esto Kash, lo he contestado ya aqui
http://microsoftnlayerapp.codeplex.com/Thread/View.aspx?ThreadId=227211
Después de una serie un poco grande de post sobre una temática concreta siempre está bien hacer una pequeña