Entity Framework 4.1 CF y Lazy Load

Para finalizar esta serie de post sobre Entity Framework 4.1 CF, vamos a hablar de una nueva caracteristica: soporte de Lazy Load (Carga Diferida).

Comencemos con una definición general de Lazy Load para que nos demos una mejor idea de que estamos hablando:

El Lazy Loading es un patron de diseño util y simple que se basa en ir cargando los distintos componentes de una clase cuando los vamos usando.

Ahora vamos a ver como trabaja este patrón de diseño dentro del framework EF CF 4.1.

En la definición anterior explica que Lazy Loading tiene como finalidad ir cargando los distintos componentes de una clase a medida que lo vamos usando. Esos componentes en EF se representan por medio de las llamadas propiedades de navegación, las cuales nos proporcionan una forma de navegar de una asociación o relación entre dos tipos de entidades, retornando una referencia a un objeto (si la relación es de cero a uno o uno a uno) o una colección (si la relación es de uno a muchos).

En nuestro ejemplo las propiedades de navegación son: Eventos que pertenece a la clase Agenda y Agenda que pertenece a la clase Evento:

1:     public class Agenda
2:     {
3:         public int AgendaId { get ; set ; }
4:         public string Propietario { get ; set ; }
5:         public DateTime FechaCreacion { get ; set ; }
6:
7:         public virtual ICollection <Evento> Eventos { get ; set ; }
8:     }
1:     public class Evento
2:     {
3:         public int EventoId { get ; set ; }
4:         public int AgendaID { get ; set ; }
5:         public DateTime Fecha { get ; set ; }
6:         public string Comentario { get ; set ; }
7:
8:         public virtual Agenda Agenda { get ; set ; }
9:     }

Notece que por convención dichas propiedades son marcadas como virtual (si no las marcamos de esta forma, no podremos aprovechar las ventajas de LazyLoad).

Antes de escribir nuestra primer linea de código, quiero comentarles que Lazy Loading en EF 4 viene habilitada por default. Esto no es del todo apropiado, sobre todo cuando el volumen de datos es demasiado grande o en el caso de que solo quiera recuperar, por ejemplo, un listado de agendas, donde no me interesa conocer todos sus eventos asociados. Para evitar esto, vamos a decirle al DbContext que por defecto esta característica – LazyLoadingEnabled – venga des-habilitada. Entonces modificamos el constructor de nuestro DatosContext:

1: public class DatosContext : DbContext
2: {
3:     public DbSet<Agenda> Agendas { get; set; }
4:     public DbSet<Evento> Eventos { get; set; }
5:
6:     public DatosContext() : base("name=DatosContext") 
7:     {
8:         this.Configuration.LazyLoadingEnabled = false; 
9:     }
10: }

Ahora sí, ya tenemos nuestro entorno listo, comencemos!

Lo primero que debemos hacer es crear y grabar una agenda y luego asignarle un par de eventos (de esta forma podremos visualizar mejor los ejemplos). Una forma simple de realizar esto es sobre-escribir el método Seed() de la clase DatosInitializer tal como lo explicamos en el primer post de esta serie.

Ya conocemos la forma en que se relacionan nuestras entidades, por lo tanto vamos a hacer uso del método Include() que nos proporciona la clase DbQuery. También podemos hacer uso de la extensión Include() provisto por DbExtensions (para este caso recordemos importar System.Data.Entity).

Include() es el método que nos permite obtener de una consulta el set completo de datos de una entidad y de todas sus relaciones.

Generalmente para recuperar la lista de alguna entidad (en nuestro caso de agendas) escribimos la siguiente consulta:

1: public ActionResult Index()
2: {
3:     var agendas = datos.Agendas.ToList();
4:
5:     return View(agendas);
6: }

Sin embargo, esto no nos recupera la lista de eventos asociados a cada agenda (siempre y cuando hayamos desactivado la característica de Lazy Loading). Inspeccionando la primer agenda de la lista podemos afirmar esto:

Inspeccionando objetos obtenidos con EF4.1 sin LazyLoad

Inspeccionando objetos obtenidos con EF4.1 sin LazyLoad

Para poder recuperar la agenda y sus eventos asociados debemos hacer uso del método Include() donde le pasaremos como parametro la propiedad de navegación de la cual queremos obtener los datos:

1: public ActionResult Index()
2: {
3:     var agendas = datos.Agendas.Include("Eventos").ToList();
4:
5:     return View(agendas);
6: }

Ahora vemos los mismos objetos obtenidos con LazyLoad:

Inspeccionando objetos obtenidos con EF4.1 con LazyLoad

Inspeccionando objetos obtenidos con EF4.1 con LazyLoad

Como observamos, se han recuperado también los Eventos de la agenda.

Para finalizar veamos algunos ejemplos más de lo que podemos hacer con EF y Lazy Load:

1:// Recupero todas las relaciones entre agenda y eventos utilizando DbQuery.
2:// La asociación se especifica por medio de un string.
3:var ag = datos.Agendas.Include("Eventos").ToList();
4:
5:// Recupero todas las relaciones entre agenda y eventos utilizando DbExtensions
6:// La asociación se especifica por medio de una expresion lambda.
7:var ae = datos.Agendas.Include(e => e.Eventos).ToList();
8:
9:// Recupero una agenda creada en el día de hoy y sus eventos.
10:var a1 = datos.Agendas
11:          .Where(a => a.FechaCreacion == DateTime .Now)
12:          .Include(e => e.Eventos)
13:          .FirstOrDefault();

Espero que le haya sido de utilidad.

Anuncios

8 comentarios en “Entity Framework 4.1 CF y Lazy Load

    • La asociación, si entendí bien la pregunta, la haces al momento de definir el modelo. En nuestro caso estamos creando dentro de la clase Evento una propiedad del tipo virtual que es una Agenda (ya con eso basta para que EF entienda que tenemos una relación entre un evento y una agenda).

      Te recomiendo el siguiente articulo donde se detallan varias de las convenciones utilizadas EF para definir relaciones y claves al momento de definir el modelo: http://blogs.msdn.com/b/efdesign/archive/2010/06/01/conventions-for-code-first.aspx

      Espero que esa sea la respuesta que estabas buscando, cualquier cosa la seguimos.

      Abrazos!

      • Lo siento creo que hice mal la pregunta por pensar dos cosas al mismos tiempo xD, mi duda es la siguiente
        como haces para que en la misma vista(me refiero a las vistas del mvc) donde ingresas los datos de un nuevo registro en la tabla “Agenda” puedas ingresar los datos de los eventos asociados a esta y cuando le des submit puedas guardar todo de una sola ves por ejemplo tu creas una nueva agenda y te sale una vista con los campo:
        Propietario:_________
        Fecha de creacion:__________

        Pero adicionalmente quieres que salga en esa misma vista los datos de los eventos que asociaras a ella

        al final seria algo parecido a esto:

        Datos de la agenda————————————————————————————————————————
        | Propietario:____________ | Fecha de creacion:_____________ | | |
        |__________________________________________________________________________________ |

        Eventos asociados a esa agenda—————————————————————————————————–
        | Datos Evento1…… |
        | Datos Evento2…… |
        | Datos Evento3…… |
        | …… |
        |__________________________________________________________________________________ |

      • Hola Rene, es posible hacer lo que dices, para tu caso entre la vista y el controlador deberán viajar los datos de la agenda y sus eventos. Te aconsejo manipular con jQuery la carga de los eventos en la vista.

        Luego al momento de grabar el set completo de datos, lo que puedes hacer es grabar en primer instancia la Agenda, y luego sus eventos, asignándoles a cada uno de ellos la agenda recientemente creada.

        Espero que haya sido claro y cualquier duda la seguimos.

        Abrazos.

  1. Gracias Sebis, una ultima duda como seria la mejor manera de realizar el proceso de grabado de datos, llamando dentro del controlador de la agenda(por ejemplo crear un objeto EventoController dentro del metodo create de la agenda) al controlador de los eventos y ejecutar directamente la funcion create del controlador de los eventos o se puede hacer de una mejor manera, y la validacion de datos como podria realizarla para que los datos de los eventos se puedan validar de igual manera que los datos de la agenda los valido usando el htmlHelper de la vista(por ejemplo EditorForModel(model=>Model.Propietario)

    • Hola Rene. Si los eventos forman parte del modelo, no es necesario que generes nada “extraño”, ya que se van a validar de la misma forma que cualquier otro atributo del modelo (recomiendo que trabajes con la librería System.ComponentModel.DataAnnotations para esto).

      En cuanto a la grabación de los eventos, haría que formen parte de la misma transacción que graba los datos de la agenda, o que la misma acción se invoque luego de generar la Agenda.

      Cualquier cosa envíame una copia del proyecto y los revisamos juntos.

      Abrazos.

  2. Hola Sebys, consulta… conoces como implementar IOC – ejemplo MS Unity – utilizando database first mediante archivos edmx?. tengo una duda y no logro encontrar la solucion, es posible registrar container.registertype para utilizar la informacion contenida en el mismo?. mas que agradecido por la orientacion.
    slds,

    • Hola Sebastian. No logro entender cual es tu problema, podrías darme un ejemplo de lo que necesitas hacer? En cuanto a la segunda pregunta, puedes registrar distintas instancias que podrían trabajar con “distinta” información contenida en la misma base de datos.

      Abrazos!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s