EF 4.0: POCO y proxies dinámicos

Para ser sinceros, entre el comienzo del nuevo libro de EF 4.0 y el papel en blanco que esto representa, no sabía por dónde empezar a escribir sobre EF. Son tantas y en mi opinión tan acertadas las nuevas novedades que no tenía ni idea del sitio en el que poner mi granito de arena.

Desde la primera versión, y por ahora única, de Entity Framework, muchas han sido las reclamaciones y recomendaciones de mejora que este framework ha recibido por parte de la comunidad, seguro muchos conocéis el famoso “Vote of No Confidence”  que algunos MVP firmaron y que tanto revuelo levanto en su tiempo. De todas las recomendaciones y falta de confianza en esta primera versión del producto una muy comentada fue el hecho de no poder disponer de objetos POCO dentro de nuestro modelos de dominio, algo imprescindible para incluir el concepto de ignorancia de la persistencia, PI ( Persistent Ignorant ) dentro de nuestros desarrollos.

Por suerte, en esta segunda versión esta feature tan solicitada está disponible dentro de la nueva versión del producto, así como plantillas T4 para la generación automática de las clases del modelo. Para una introducción rápida podéis leer los infinitos blogs que tratan este tema, y como no, en esta misma comunidad mis vecinos de blog, Juan Carlos y Alberto Diaz tienen entradas relativas que recomiendo leer.

Objectos POCO

Para no repetirme en el tema, en mi entrada me gustaría comentar algunas interioridades de estos objetos POCO y como trabajan internamente. Me imagino, que al igual que yo, una pregunta que os haréis es como se gestionan los cambios que sobre estos objetos se producen, dentro del ámbito de un contenedor, para que posteriormente puedan ser llevados hasta el almacen relacional configurado y como se manejan las relaciones entre los mismos.

Pongámonos en contexto y empecemos definiendo, tal y como muestran las entradas anteriormente mencionadas, un par de entidades, que denominaremos Blog y Post, mostradas a continuación.

 

   1:  public class Blog
   2:  {
   3:          #region Properties
   4:   
   5:          public int Id { get; set; }
   6:   
   7:          public string Title { get; set; }
   8:   
   9:          public string Description { get; set; }
  10:   
  11:          List<Post> Posts { get; set; }
  12:   
  13:          #endregion
  14:  }

 

   1:  public class Post
   2:  {
   3:          public int Id { get; set; }
   4:   
   5:          public string Title { get; set; }
   6:   
   7:          public string Body { get; set; }
   8:   
   9:          public int BlogId { get; set; }
  10:   
  11:          public Blog Blog { get; set; }
  12:  }

 

Ahora realicemos una sencilla operación de cambio en un conjunto de entidades, por ejemplo los blogs almacenados en nuestro almacen de datos:

   1:  using (BlogModelContainer container = new BlogModelContainer())
   2:  {
   3:         List<Blog> blogs = container.Blogs.ToList();
   4:         blogs.ForEach(blog => blog.Title = "Changed in code!");
   5:   
   6:         container.SaveChanges();
   7:  }

 

Si comprobamos nuestra base de datos veremos como estos cambios se han realizado correctamente, ¿como es posible esto? Fijaos que en nuestras clases Blog y Post ya no disponemos de los eventos RaisePropertyChanged que notificaba a la infraestructura un cambio en el valor de esta propiedad, sin embargo todo sigue funcionando correctamente. Como os podéis haber imaginado alguien se ha encargado de sincronizar nuestros objetos POCO con  los elementos que manejan el estado de todas las entidades dentro de la infraestructura de Entity Framework, nuestras ya famosas e hiper-conocidas ObjectStateEntry.

Este proceso de sincronización de cambios puede realizarse de dos formas diferentes, la primera de forma imperativa mediante una llamada a un nuevo método de los contextos de trabajo llamado DetectChanges, y el segundo, como hemos visto en nuestro objeto, de forma implícita en la llamada a SaveChanges, el cual en su implementación ya realiza este proceso por defecto.

Por supuesto, por poner pegas que no sea, este sistema no es del todo eficiente, pensemos que en realidad el proceso es básicamente la creación de un snapshot de las entidades materializadas y posteriormente comparar estos snapshot con los elementos a guardar para conocer o sincronizar los cambios. ¿Cómo podemos mejorar este proceso? La respuesta es mediante los “Change Tracking Proxies” de los cuales hablaremos a continuación.

 

Algunas notas importantes sobre los Objetos POCO

Una característica que los objetos POCO también deben soportar es el manteniemiento de las relaciones entre los objetos,asegurando la consistencia de las relaciones. Aunque este trabajo lo podemos hacer nosotros a mano tal y como se muestra en el siguiente enlace en la sección Fix-up relationships la plantilla por defecto que el equipo de producto de EF nos ofrecerá por defecto ya contendrá esta característica funcamental.

 

Change Tracking Proxies

 

Un Change Tracking Proxy no es mas que una subclase de nuestros objetos POCO que implementa la infraestructura de gestión de cambios que se define en Entity Framework, es decir, implementa la interfaz IEntityWithChangeTracker Por supuesto, con solo decir que es una subclase ya estamos imponiendo una  serie de restricciones dentro de nuestros objetos, por ejemplo el hecho de que no pueda ser una clase sellada. A continuación se muestra una lista de las restricciones que se deben de cumplir para disponer de esta capacidad dentro de nuestros objetos:

 

  1. Las clases POCO no pueden estar selladas
  2. Las clases POCO tienen que tener un constructor por defecto público.
  3. Las propiedades deben declararse como publicas y virtuales para que puedan ser sobreescritas por la subclase.
  4. El tipo de las propiedades de navegación debe de ser ICollection<TEntity>

Veamos un ejemplo en la práctica modificando nuestras entidades anteriores para que cumplan estas restricciones:

 

   1:  public class Blog
   2:  {
   3:          #region Properties
   4:   
   5:          public virtual int Id { get; set; }
   6:   
   7:          public virtual string Title { get; set; }
   8:   
   9:          public virtual string Description { get; set; }
  10:   
  11:          public ICollection<Post> Posts { get; set; }
  12:   
  13:          #endregion
  14:  }

 

   1:  public class Post
   2:  {
   3:   
   4:          #region Properties
   5:   
   6:          public virtual int Id { get; set; }
   7:   
   8:          public virtual string Title { get; set; }
   9:   
  10:          public virtual string Body { get; set; }
  11:   
  12:          public virtual int BlogId { get; set; }
  13:   
  14:          public virtual Blog Blog { get; set; }
  15:   
  16:          #endregion
  17:  }

 

Si realizamos un pequeño ejemplo de cambio en una entidad y observamos los valores que el objeto ObjectStateEntry asociado a la entidad tiene en sus valores originales y actuales podremos ver ‘la magia’ de nuestros “change tracking proxies”.

 

   1:  using (BlogModelContainer container = new BlogModelContainer())
   2:  {
   3:                  Blog firstQueriedBlog = container.Blogs.First();
   4:                  firstQueriedBlog.Title = "Changed in code!";
   5:   
   6:                  ObjectStateEntry entry = container.ObjectStateManager.GetObjectStateEntry(firstQueriedBlog);
   7:   
   8:   
   9:                  string original = entry.OriginalValues["Title"].ToString();
  10:                  string current = entry.CurrentValues["Title"].ToString();
  11:   
  12:                  Console.ReadLine();
  13:  }

 

 

¿De dónde viene esta “magia”? Si observamos con detalle el tipo de Blog obtenido veremos como en realidad el resultado es una subclase emitida en tiempo de ejecución que hará de proxy de nuestros objetos POCO. De esta forma tenemos PI en nuestros desarrollos y rendimiento en la gestión de los cambios de los mismos.

img1

Algunas notas importantes sobre Change Tracking Proxies

 

Aunque el uso de proxies dinámicos es una buena solución, en mi opinión mejor que la inyección de IL como proponen otros MVP , también tienen algunas consideraciones que debemos tratar. La primera y más imporatante es como afectan estos proxies en aplicaciones N-Tier en las que podríamos serializar estas entidades como contratos de datos, puesto que no sabemos a priory el nombre del tipo creado y por lo tanto no lo podremos establecer como KnownType o ServiceKnowType para facilitar el proceso de serialización. Con el fin de soportar esta problemática WCF 4.0 dispone de un nuevo mecanismo para resolver dinámicamente los tipos conocidos por medio de un nuevo elemento llamado DataContractResolver, sobre el cual podréis leer aquí y aquí.

Published 19/1/2010 1:20 por Unai
Comparte este post:
http://geeks.ms/blogs/unai/archive/2010/01/19/ef-4-0-poco-y-proxies-din-225-micos.aspx

Comentarios

# re: EF 4.0: POCO y proxies dinámicos

Pues tendremos que probar el Change Tracking Proxies y WCF con un cliente Java a ver que tal se comporta. Tiene buena pinta!

Tuesday, January 19, 2010 9:58 AM por Alberto Diaz Martin

# re: EF 4.0: POCO y proxies dinámicos

Alberto no te confundas. Change Tracking Proxy se refiere solamente a la gestión de cambios dentro de un contexto de trabajo, no si mueves estos fuera por medio de una capa de servicios.

saludos

Tuesday, January 19, 2010 10:24 AM por Unai

# re: EF 4.0: POCO y proxies dinámicos

Ya veo que dependemos del contexto para que el proxy haga el tracking de los cambios.

Tuesday, January 19, 2010 11:54 AM por Alberto Diaz Martin

# re: EF 4.0: POCO y proxies dinámicos

Uno de los problemas que continuo viendo es la referencia a los campos. En la linea 'string current = entry.CurrentValues["Title"].ToString();', se hace referencia a la columna "Title". ¿Hay alguna forma de resolver esto en EF 4 para evitar errores si cambiamos de nombre el campo de la entidad o de la base de datos ?

Un Saludo.

Tuesday, January 19, 2010 2:32 PM por Juan Irigoyen

# re: EF 4.0: POCO y proxies dinámicos

Juan, no hay que hacer nada con respecto al tema del manejo de los nombres como Title, de hecho ahora tampoco para crear los ObjectQuery hace falta el nombre, con el tipo llega. En mi ejemplo lo uso porque accedo al ObjectStateManager no a la información de un tipo.

Saludos

Unai

Tuesday, January 19, 2010 6:21 PM por Unai

# re: EF 4.0: POCO y proxies dinámicos

¿Se podria al definir una herecia entre tablas establecer una codicion diferente a la igualdad de un campo?, por ejemplo si un campo es mayor que un valor dado que sea un tipo y si es menor o igual que sea de otro.

Saludos

Angel.

Tuesday, May 11, 2010 11:59 AM por Angel

# re: EF 4.0: POCO y proxies dinámicos

Unai, cual crees que el la mejor alternativa para una arquitectura de aplicaciones distribuidas .NET a .NET (Cliente y Servidor)...POCOs o STEs?

Thursday, August 12, 2010 9:02 PM por Martin

# EF 4.0 Performance Tips #7

Al final está saliendo una lista interesante de tips a tener en cuenta, y la verdad, cuando empecé a

Saturday, September 11, 2010 4:10 PM por O bruxo mobile

# EF4 Code First, MVC2 y Unity para atarlo todo un poco…

Buenas! No soy ni mucho menos un experto en EF (es más, me acabo de poner), como pueda serlo p.ej. Unai

Friday, September 24, 2010 12:58 PM por Burbujas en .NET