Una de las posibilidades que nos dan los ORM's como Entity Framework, consiste en la carga de una forma simple de las entidades relacionadas. Es decir, el poder cargar los datos de otras tablas relacionadas con nuestro objeto directamente, simplemente accediendo a su propiedad.
Con un ejemplo lo veremos mejor. Tenemos dos entidades sencillas que son los usuarios y los pedidos de esos usuarios:
public class Usuario{
public int Id { get ; set ; };
public int Nombre;
public int Apellido;
....
List<Pedido> Lista_Pedidos;
}
public class Pedido{
public int Id;
public DateTime Fecha;
}
Como veis, el usuario tiene una serie de campos propios: id, nombre, apellidos, etc... y también una colección de la clase pedidos. En un entorno tradicional, tendríamos un objeto de la clase usuario con sus datos cargados. Para poder acceder a sus pedidos tendríamos que cargarlos previamente, aquí es donde entra el Lazy Load o carga diferida. Si la tenemos configurada, para acceder a los datos de los pedidos simplemente deberíamos acceder a esa colección desde el objeto usuario.
int id _pedido = usu.Lista_Pedidos.First().Id;
Este ejemplo no tiene mucho sentido, pero con él vemos claramente que con un objeto usuario podemos acceder al Id del primer pedido sin tener que cargarlos previamente.
Como veis, es muy cómodo y sencillo de usar, pero esto tiene un peligro, cada vez que se accede a los datos anidados se produce la consulta a la base de datos. Si sólo se necesita extraer un objeto concreto, no habrá ninguna problema pero... ¿y si se va a acceder a todos los pedidos de este usuario dentro de un foreach?:
foreach (Usuario usu in usu.lista_pedidos){
int id _pedido = usu.Lista_Pedidos.First().Id;
}
En este caso, se estaría haciendo una pequeña consulta por cada pedido que tenga el usuario, es decir, si tiene miles de pedidos, estaríamos haciendo miles de pequeñas consultas!!!
¿Qué se puede hacer para evitar esto? Siempre que queramos acceder a un gran número de elementos de una colección anidada, deberíamos traer de la BD todos estos datos anteriormente. ¿Cómo?:
-
Haciendo un include para cargar los datos relacionados al traernos los datos de la primera entidad:
Usuario usu = contexto.usuarios.Where(c=>c.usuario.id==1).Include("Pedidos").First();
//Include usando un string para refernciar la tabla anidada
o
Usuario usu = contexto.usuarios.Where(c=>c.usuario.id==1).Include(t => t.Pedidos).First();
//Include con expresión lamba, solo disponible en las últimas versiones
- La segunda opción seria una vez que ya teníamos esta entidad cargada, podemos forzar cargar todos sus datos de una vez:
usu.Lista_Pedidos.Load();
Con esta sencilla instrucción ya tendríamos todos los datos en memoria
Viendo ésto, hay posibles escenarios en los que podrías pensar que es mejor que este Lazy Load no estuviese ahí, ya que puede producirnos graves problemas de rendimiento sin enterarnos.
Por defecto en Entity Framework, el lazy load viene activado al crear un contexto de conexión, pero de ser necesario podríamos desactivarlo de una manera sencilla. Para ello, accedemos al .edmx del contexto, y dentro de sus propiedades desactivamos la opción "Carga diferida habilitada":