Self-Tracking en Entity Framework 4.0

Una de las nuevas características que se han desarrollado en Entity Framework 4.0, es la posibilidad de usar entidades Selft-Tracking. Las entidades Self-Tracking son clases que no tienen dependencia de Entity Framework, pero que incluyen mecanismos que gestionan los cambios es sus propiedades.

Estas entidades nos permiten enviarlas a un cliente (por medio de WCF, por ejemplo), realizar cambios sobre ellas y recibirlas conociendo que cambios se han realizado, sin necesidad de consultar el contexto. Con estos cambios y con algunas nuevas funcionalidades de Entity Framework 4 se obtiene un mejor rendimiento cuando persistimos las entidades en el contexto.

Cada clase de nuestro modelo implementa la interfaz IObjectWithChangeTracker, que tiene los métodos necesarios para gestionar los cambios (Unchanged, Modified, Added o Deleted), y no sólo gestiona los cambios, sino que también mantiene los valores originales.

Para generar las entidades Selft-Tracking nos tenemos que instalar la CTP2 de Entity Framework, que la podemos descargar aquí.

Una vez instalada la CTP2, tendremos una nueva opción en nuestro modelo (fichero edmx) que nos permite añadir un nuevo elemento de generación de código.

EF_SelfTracking1 

y en la ventana de nuevo elemento, tenemos la opción del generador de entidades Selft-Tracking de ADO.NET (ADO.NET Selft-Tracking Entity Generator)

EF_SelfTracking2

¿Qué hemos conseguido con esto? Bueno, si revisamos nuestro Solution Explorer, podemos observar que se han creado dos nuevos elementos, ClientesModel.Context.tt y ClientesModel.Types.tt.

EF_SelfTracking3

Estos dos nuevos ficheros son plantillas de texto T4 que se utilizan para generar código. Estas plantillas generan las clases necesarias para Selft-Tracking, tanto para el Contexto como para nuestras entidades del modelo. Más información sobre plantillas T4 en el siguiente post.

Ahora tenemos generados el código necesario para nuestro Selft-Tracking Context y para nuestras Entidades Self-Traking, pero ¿es recomendable dejar nuestras entidades en el mismo proyecto que nuestro contexto? Si lo que queremos es desarrollar una aplicación N-tier, la respuesta es no, lo ideal, para poder reutilizarlo en todas nuestras capas, sin dependencias de Entity Framework, sería separar la plantilla ClientesModel.Types.tt en otro proyecto para que pueda ser utilizado en cualquier capa de nuestra aplicación.

Veamos cómo debería de quedar.

EF_SelfTracking4

Al separar nuestras entidades (ClientesModel.Types.tt), tendremos que hacer ciertos cambios en estas plantillas para que la generación y las referencias sean las correctas.

  1. Añadimos en el proyecto Data la referencia al proyecto Model.
  2. Las entidades Self-Tracking se generan con la capacidad de que puedan ser serializadas, necesitaremos añadir la referencia a System.Runtime.Serialization al proyecto Model.
  3. Modificamos la plantilla ClientesModel.Types.tt para que genere nuestro modelo a partir del fichero edmx. Cambia la ruta de la variable string inputFile = @”ClientesModel.edmx” a @”..EfTracking.DataClientesModel.edmx”.
  4. Por último, modificamos la plantilla ClientesModel.Context.tt para que incluya los using necesarios para que utilice nuestras entidades que están en el namespace EfTracking.Model. Buscamos las dos secciones de using que se encuentran en la plantilla y añadimos la nuestra.

Con estos cambios, conseguimos distribuir nuestras entidades, incluyendo la plantilla de generación del código, en otro proyecto (dll) para su reutilización en cualquiera de las capas (cliente, servicio, datos, etc.). Al incluir la plantilla, mantenemos su funcionalidad que nos permitiría modificar nuestro Entity Framework (fichero edmx) y que se reflejen los cambios en las entidades Self-Tracking.

Si nos creamos un servicio que utilice las entidades y el contexto, con Self-Tracking podemos obtener nuestra entidad y realizar la actualización de la misma, utilizando el siguiente método:

   1: public Model.Contact UpdateContact(Model.Contact contact)

   2: {

   3:     using (var context = new Data.ClientesEntities())

   4:     {

   5:         context.Contacts.ApplyChanges(contact);

   6:         context.SaveChanges();

   7:      

   8:         return contact;

   9:     }

  10: }

 

El método ApplyChanges es una nueva funcionalidad que permite enlazar las entidades e interpretar los cambios realizados para persistirlos a nuestro contexto.

Tenemos que tener en cuenta que implementando la funcionalidad de Self-Tracking en nuestra aplicación, limitamos la interoperabilidad de nuestra aplicación ya que no podemos asegurar que la funcionalidad de Self-Tracking sea manejada por clientes no .NET.

Sin embargo, siempre hay que valorar si necesitamos esta nueva funcionalidad frente a poder interactuar con otros sistemas que no la pueden implementar.

 

Saludos a todos…

12 pensamientos en “Self-Tracking en Entity Framework 4.0”

  1. Hola, gracias por este tutorial
    Quería saber si me podes ayudar con una duda Alberto. Supongamos que agrego las dos capas como comentas en el tutorial y agrego otra capa más para usarla de vista, por ejemplo un proyecto web. Al proyecto de la capa web le agrego las referencias para poder usar un “Contact” y claro esta el que pones como ejemplo ” UpdateContact()”.
    La duda sería que si agrego un solo contacto por vez no hay problema, pero que pasa si en un form tengo que usar varias veces ” UpdateContact()”
    como hago para que sea transaccional????
    Porque ahora que tengo todo en una capa no hay problema porque el mismo entity framework lo hace, por ejemplo tengo algo así:

    Producto.ApplyChanges(Producto_01)
    Producto.ApplyChanges(Producto_02)
    _EFmodel.SaveChanges();

    Es solo un ejemplo, pero con SaveChanges() (que lo tengo dentro de un try/catch) si el segundo producto da error por alguna razón, el primer producto no queda grabado.

    Pero esto no se como solucionarlo con capas, porque tener una capa de datos que tiene como vos comentas un metodo “UpdateContact()” y otro “AddContact()”, “DeleteContact()” por ejemplo, ya la capa web al no usar el “model” del entity f. ya no tiene una forma para este tipo de transacciones. Quería saber esto como podría solucionarlo esto. Gracias y un cordial saludo

  2. Hola Hector, ¿y si creas un método en tu servicio que sea capaz de actualizar en base a una lista de Productos?

    No intentes hacer los cambios de cada uno de los productos a través del servicio, pásale al servicio la lista de cambios y que el sea el que se encargue de pelearse con el contexto.

    Esta sería la opción más sencilla, otra podría pasar por serializar el contexto pero puede complicarse un poco el desarrollo.

  3. Buenas, tengo una duda que no me deja avanzar en mi proyecto. Al principio de usar Entity Framework digamos que las entidades de dominio (p.e: user, order, transfer…) residian implícitamente en la capa de acceso a datos, en el modelo de entidades que creaba a partir de la base de datos, saltandome el modelo de capas.
    Después de leer su blog he visto que se puede crear otro proyecto de entidades para asi meter dichas entidades ahí y separarlas para no romper el principio de capas.
    Lo que pasa que al hacer los pasos de este blog ahora desde la capa de lógica de negocio cuando intento acceder al método .addToUser (por ejemplo) ya no me sale, tan sólo me sale .addToObject(String EntitySet, Object).
    Sin embargo de la otra manera, antes de separar las entidades sí podía acceder a estos métodos para hacer los insert, update, delete…

    ¿Podría ayudarme?

    Otra pequeña gran duda es…¿Cuál es la diferencia entre POCOS, IPOCOS y Self-traking?. ¿Es todo lo mismo?….vienen a ser los Transfer Objects de la aplicación???

    Muchas gracias de antemano.

  4. Hola Juanma, cuanto utilizas SelfTracking tienes que tener en cuenta que no se utiliza el método AddObject del Context, sino que se emplea context.ENTIDAD.ApplyChanges(contact); y a continuación context.SaveChanges();.

    Estos métodos se encargan de identificar los cambios en las entidades y aplicarlos al contexto.

    POCO e IPOCO se refieren a la forma en que se declaran las clases, por ejemplo, POCO (http://geeks.ms/blogs/adiazmartin/archive/2010/01/17/poco-en-entity-framework-4-0.aspx) es Plain Old CRL Object o lo que es lo mismo clases sencillas. Cuando utilizamos estas clases y trabajamos desconectados del Context, tenemos el problamos que no podemos llevar un control de los cambios que se producen en ella; para eso tenemos SelfTracking (http://geeks.ms/blogs/adiazmartin/archive/2010/01/18/self-tracking-en-entity-framework-4-0.aspx), es una implementación que permite a las clases ‘auto-gestionarse’ y mantener un control de los cambios que se producen para que cuando lleguen al Context los pueda manejar.

  5. Muchas gracias por tu respuesta!
    Pero…sigo sin verlo claro. Estoy haciendo una aplicación en 3-capas. Me podrías poner un ejemplo sencillo de una insercción y un update en la base de datos??, supongamos que es de una tabla Usuario(dni, nombre, apellido).

    Así quizás lo vea más fácil.

    Gracias!

  6. cuando utilizas SelfTracking, el Context no es el mismo que si utilizas EF por defectto. El método que se utilizar tanto para inserción como para actualización es el mismo (ApplyChanges). El context de SelfTracking es el que se encarga de identificar si tiene que realizar un insert o un update.
    Te dejo un enlace que habla de N-Tier con EF4 http://msdn.microsoft.com/en-us/magazine/ee335715.aspx
    y un proyecto de ejemplo con métodos de Insert and Update desde el servicio http://cid-77af67c35753916e.office.live.com/self.aspx/P%c3%bablico/STESolution.rar

  7. Buenas!, tengo montado un proyecto VS2010 C# y he usado Entity Framework 4.0. Además he usado como objetos entidades los Self-Tracking.
    Sé que cuando abstraemos la BD con dicho framework, él solo te crea los métodos de insercción, actualización, etc… pero tengo una duda, ¿Cómo puedo hacer si además de los métodos que crea el entity framework, necesito uno q no venga?Por ejemplo, si quiero insertar un usario por id y no viene??o si quiero hacer una busqueda con 2 tablas que tienen campos relacionados a través de una FK???
    Me explico, si tengo en una tabla Colores(id_colores, colores) y otra tabla Coches(id_coche, ….., id_color) yo lo que quiero es que me devuelvo el string del color no el int???
    No sé si se me entiende. En definitiva poder crear yo los métodos de la capa de acceso a datos que no me haya creado el framework.

    Gracias!

  8. Juanma, EF4 no sustituye la capa de acceso a datos, EF4 se encarga de la persistencia de los objetos. Debes de desarrollar tu capa de acceso a datos con las consultas Linq to Entities que necesites.

  9. Yo creía q con Entity Framework ya no era necesario hacer todas las clases DAL, como por ejemplo userDAL y q no habia q hacer todos los métodos de insercción, actualizacion, borrado… pues ya lo hacía el framework.
    De hecho, hice parte de la capa lógica de negocio y usé los métodos q creaba el framework como por ejemplo con User.

    namespace 3-tier.BusinessLogicLayer
    {
    public class UsuarioBL
    {
    3tier context;

    public UsuarioBL()
    {
    context = new 3tier();
    }

    public void insertarUsuario(Usuario u)
    {
    context.Usuario.AddObject(u);
    context.SaveChanges();

    }

    public Usuario buscarUsuario(String nombre)
    {
    Usuario user = context.Usuario.FirstOrDefault(u => u.usuario == nombre);
    return user;
    }
    }
    }

    Tal vez esté un poco liado, ¿Podría explicarme que hago mal? (aunque el código funcina, devuelve el usuario y lo inserta)
    Insisto en que en la capa de acceso a datos solo tengo el módelo .edmx

    Gracias y perdona por las molestias.

  10. Juanma, no estás haciendo nada mal, pero desde el punto de vista de la arquitectura, tu Business Layer no es independiente de EF4, lo ideal sería crear una Data Layer para que la dependencie exista en esa capa y no en la Business. Pero lo dicho, no es más que una mejora de arquitectura.

  11. Alberto, excelente post. Algunas dudas sobre la arquitectura. En la capa de DAL se sigue usando EF normalmente, solo que desde la capa de negocios se utiliza el ObjectTracker para los cambios de las entidades “livianas” que viajan entre capas. Es así?
    En la capa de servicio (WCF) es donde estará la lógica de negocios de nuestro sistema?
    Tengo intención de utilizar MVC 4 como arquitectura de desarrollo para las vistas. Cual vendría a ser el modelo en este caso? Utilizaria las entidades Self-Tracking como modelo que se presenta en las vistas o tengo que crear unas nuevas y tomarme el trabajo de mapearlas con las que me llegaron desde el servicio? Si tengo que utilizar las Self-Tracking, como se resuelve el tema de los Data Annotations por ejemplo para la validación? Desde ya muchas gracias!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *