Self-Tracking Entities en Entity Framework 4

por emmanuel  24. agosto 2010

Introducción: tipos de entidades en Entity Framework

Desde la salida de Entity Framework, al generar modelos de entidades, las clases generadas derivan de EntityObject.
Con la salida de la versión 4 de Entity Framework, se incorpora soporte para seleccionar el tipo de entidad de la cual van a derivar nuestras entidades de negocio: a los clásicos EntityObject se agregan como novedad POCO, POCO Proxies y Self-Tracking entities.
Antes de desarrollar las entidades de tipo Self-Tracking (el objetivo de este artículo), es conveniente dar un panorama de estos diferentes tipos de entidades, para poder decidir cual utilizar, dependiendo de la arquitectura de la aplicación a realizar:

  • EntityObject

Por defecto, las herramientas de ADO.NET Entity Data Model generan tipos de entidades que derivan de EntityObject. En este caso, el ObjectContext administra las relaciones entre los objetos, mantiene el historial de los cambios que ocurren (Change-Tracking) y soporta Lazy Loading.

Sin embargo, este tipo de entidades dependen fuertemente del Entity Framework. Si se desea trabajar con arquitecturas que no conocen la forma de persistencia (por ejemplo: TDD, Test-Driven Development), lo más deseable es utilizar entidades de tipo POCO o POCO Proxy.

  • POCO

Entity Framework permite utilizar objetos del dominio existentes junto con el modelo de datos, sin hacer cambios a las clases de datos. Estas clases POCO ("Plain-Old" CLR Objects), son conocidas como objetos que ignoran la persistencia y soportan las mismas funcionalidades de Query, Insert, Update y Delete que los objetos EntityObject.

Al trabajar con entidades POCO, los cambios que se realicen al grafo de objetos no son mantenidos automáticamente por Entity Framework a medida que ocurren, sino que se utiliza un mecanismo de snapshots para detectarlos: se debe llamar a DetectChanges para sincronizar el ObjectContext con el grafo actualizado (por defecto, el ObjectContext llama a este método antes de grabar los datos).

Este mecanismo utiliza mas memoria que el anterior y puede afectar la performance, especialmente si la aplicación requiere la detección de cambios frecuentemente. Para poder tener una notificación instantánea de los cambios, se debe activar la creación de objetos Change-Tracking Proxy, y para activar Lazy Loading se debe activar la creación de Proxies de Lazy Loading.

  • POCO Proxy

Se debe utilizar en los casos en los que se requiera detección de cambios instantánea y Lazy Loading. Al utilizarlo, se tiene la misma funcionalidad que con entidades tipo EntityObject, pero con las clases del dominio separadas del Entity Framework. Los proxies se crean en tiempo de ejecución, lo que implica que las entidades generadas difieren del tipo POCO, introduciendo algunas complicaciones con la serialización. Por otra parte, la creación de proxies consume mas recursos que los objetos POCO.

  • Self-Tracking Entities

Los tres tipos definidos anteriormente funcionan correctamente en aplicaciones donde los objetos pueden ser agregados (Attach) al ObjectContext que maneja el historial de cambios. Sin embargo, cuando se desea transferir un grafo de entidades a una capa donde el ObjectContext no está disponible, se debe decidir como mantener el historial de cambios y reportar esos cambios de vuelta al ObjectContext (por ejemplo: arquitectura en capas, ambientes desconectados, arquitecturas SOA, etc.).

A partir de la versión 4 de Entity Framework, las entidades del tipo Self-Tracking pueden grabar cambios a las propiedades escalares, complejas o de navegación. Este tipo de entidades no dependen del Entity Framework, y son generadas con el template de ADO.NET Self-Tracking Entity Generator.

Self-Tracking Entities

En arquitecturas en capas, el ObjectContext puede no estar disponible en la capa que modifica las entidades. A partir de Visual Studio 2010 (con Entity Framework 4), está disponible el template ADO.NET Self-Tracking Entity Generator. Este template genera dos archivos .tt (text template):

El archivo <nombreModelo>.tt genera los tipos de entidades y una clase helper que contiene la lógica de mantenimiento de cambios, mas los métodos de extensión que permiten establecer el estado de las entidades.

El archivo <nombreModelo>.Context.tt genera un ObjectContext tipado y una clase de extensión que contiene los métodos ApplyChanges para las clases ObjectContext y ObjectSet. Estos métodos examinan la información del historial de cambios para inferir las operaciones a realizar para grabar los cambios en la base de datos.

Para acceder al template se debe hacer click derecho sobre la superficie del diseñador de entidades, y seleccionar “Add Code Generation Item”:

SelfTracking001

 

En la ventana que aparece, seleccionar “ADO.NET Self-Tracking Entity Generator”:

SelfTracking002

Al presionar “Add”, se ejecutarán los templates que crearán las clases necesarias, las cuales contendrán los métodos de extensión necesarios para trabajar con Self-Tracking:

SelfTracking003

Métodos de extensión de Self-Tracking Entities

  • StartTracking

Este método se utiliza para comenzar el Change-Tracking (rastrear cualquier cambio que ocurra en la entidad). Esto incluye propiedades escalares, colecciones y referencias a otras entidades. Las entidades de tipo Self-Tracking inician el Change-Tracking automáticamente cuando son deserializadas en un cliente a través de WCF. También se activa para nuevas entidades creadas en los siguientes escenarios:

  1. Una relación es creada entre la nueva entidad y una entidad que actualmente tiene Change-Tracking activado.
  2. Se llama al método MarkAs o AcceptChanges en una entidad.

 

  • StopTracking

Este método finaliza el Change-Tracking en una entidad.

  • MarkAs

Todos los métodos que comienzan con “MarkAs” activan el Change-Tracking. Estos métodos permiten cambiar el estado de una entidad a Added, Modified, Deleted, o Unchanged, y además retornan la misma entidad a la cual son aplicados, con el estado modificado:

MarkAsAdded cambia el estado de una entidad a Added. Las nuevas entidades Self-Tracking son creadas en este estado y con Change-Tracking desactivado.

MarkAsDeleted cambia el estado de una entidad a Deleted.

MarkAsModified cambia el estado de una entidad a Modified. Este estado también se obtiene al cambiar el valor de una propiedad en una entidad con Change-Tracking activado.

MarkAsUnchanged cambia el estado de una entidad a Unchanged. También se obtiene este estado al llamar al método AcceptChanges.

  • AcceptChanges

Este método elimina la información de Change-Tracking para una entidad y coloca el estado en Unchanged (es decir, la entidad acepta los cambios que se le realizaron).

Métodos de extensión de ObjectContext

  • ApplyChanges

Examina la información del historial de cambios contenida en el grafo de entidades e infiere el conjunto de operaciones que deben realizarse para reflejar los cambios en la base de datos. Hay dos métodos ApplyChanges, uno para el ObjectContext y otro para el ObjectSet.

Consideraciones para trabajar con entidades Self-Tracking

Finalmente, para cerrar, les dejo algunas consideraciones a tener muy en cuenta antes de utilizar este tipo de entidades:

  • Al enviar un grafo modificado a un servicio, y luego intentar continuar trabajando con el el grafo modificado en el cliente, se debe iterar manualmente por el grafo en el cliente y llamar a AcceptChanges en cada objeto para resetear el Change-Tracking.

  • Las entidades Self-Tracking no permiten realizar Lazy Loading.

  • La serialización Binaria y la serialización a objetos de administración de estados ASP.NET no es soportada por el código generado por los templates de ADO.NET Self-Tracking Entity Generator, para soportala se debe agregar el código necesario al template.

Fuentes:

Tags: ,

ADO.NET | Entity Framework | Visual Studio

Como depurar Store Procedures, Triggers y Functions de SQL Server desde Visual Studio 2008

por emmanuel  22. marzo 2010

Una tarea imprescindible en el desarrollo y programación con SQL Server es la depuración (debugging) de Store Procedures, Triggers y Functions. El debugging nos permite ejecutar paso a paso código T-SQL, establecer breakpoints, examinar el contenido de las variables y modificarlos en tiempo de depuración, etc.

Anteriormente, los desarrolladores escribían y depuraban con el Analizador de consultas de SQL Server 2000 (Query Analyzer).

Luego, el SQL Server Management Studio 2005 que lo reemplazó no tenía ningún depurador, por lo cual para poder depurar código T-SQL se utilizaba el depurador que tiene el Visual Studio 2005.

A partir de la versión 2008 de SQL Server, las capacidades de debugging ya vienen incluidas en el Management Studio (solo funcionan con una conexión contra una instancia
de SQL Server 2008), sin embargo en ciertas ocasiones es más conveniente utilizar Visual Studio para el debugging de objetos de SQL.

Requerimientos

  • Versión Professional o Team Edition de Visual Studio.
  • Es importante destacar que al depurar se detendrán todos los threads de ejecución de SQL, de modo que no es recomendable depurar en un servidor que se encuentre en producción.
  • Activar el debugging de CLR en SQL: para esto se debe primero crear una conexión a la base de datos mediante la ventana "Server Explorer" (Menú "View"). Luego dar click derecho sobre la conexión y tildar la opción "Allow SQL/CLR Debugging"

 

EnableDebugging

Permisos

Para poder depurar código SQL desde Visual Studio 2008 existen dos cuentas de usuario para considerar:

  • La cuenta de la aplicación: es la cuenta de usuario sobre la cual se ejecuta Visual Studio. Esta cuenta es una cuenta de usuario de Windows, y debe ser miembro del grupo sysadmin en el SQL Server a ser depurado.
  • La cuenta de conexión: es la identidad usada para conectarse con SQL Server (Definida en el dialogo de conexión del "Server Explorer", o en el connection string). Esta cuenta puede ser una cuenta de usuario de Windows usando Windows Authentication (en este caso es la misma sobre la cual corre Visual Studio), o puede ser una cuenta de conexión SQL, en cuyo caso debe ser miembro del rol sysadmin para poder depurar.

 

Si no se cumplen los permisos requeridos para la Depuración de SQL Server, y se intenta depurar código de SQL Server, se obtiene el siguiente error:
User 'dbo' could not execute stored procedure 'master.dbo.sp_enable_sql_debug' on SQL Server VSQL01.

Pasos para la depuración

  • Ubicar el objeto a depurar en la ventana "Server Explorer".
  • Dar click derecho sobre el objeto que se desea depurar y seleccionar "Step into ..." ("Step into Store Procedure", "Step into Function", etc.)

 

StepInto 

  • Si requiere parámetros, aparecerá un cuadro de diálogo que permite asignar los valores para cada parámetro.

 

Parametros

  • En todo momento se puede visualizar o modificar el valor de variables locales, para lo cual podemos utilizar la ventana "Locals" de Visual Studio, disponible el menú "Debug" (solo cuando la depuración ha sido iniciada), o también mediante la ventana "Watch".

 

Debug

 

 

  • Para depurar un Trigger, se debe tener en cuenta que no se le puede invocar directamente, por lo cual, lo que se puede hacer es crear un Store Procedure cuyo código fuente invoque al Trigger, y utilizar Step Into (F11 - paso a paso por instrucciones) en vez de Step Over (F10 - paso a paso por el proceso actual) para la depuración, de manera de entrar en el código del Trigger en cuestión.

 

image

En el ejemplo se muestra un store procedure que ejecuta un UPDATE sobre la tabla que tiene el trigger a depurar. Al presionar F11 sobre la instrucción UPDATE se ingresa en modo depuración al código del trigger.

 

image

Tags: ,

SQL Server

Como cerrar correctamente un proxy WCF

por Emmanuel  17. marzo 2009
Teniendo en cuenta que un proxy WCF se deriva de ClientBase<TChannel>, y que éste implementa IDisposable, la mejor manera de utilizarlo pareciera ser:
       try
       {
           using (var proxy = ProxyFactory.ObtenerProxy())
           {
               //Utilizar el proxy
           }
       }
       catch (Exception ex)
       {
           throw;
       }
 
Esta forma de utilización puede llevarnos a un error WCF cuando ocurre una excepción y el canal queda en estado “Faulted”, impidiendo cerrar el proxy.
 
Si accedemos por Reflection a la implementación de IDisposable observamos:
 
       void IDisposable.Dispose()
       {
           this.Close();
       }
 
Esta implementación no contempla el estado del proxy antes de llamar a Close(), de manera que ante cualquier error ocurrido al intentar cerrar el proxy recibiremos una excepción.
 
Una manera de corregir este comportamiento es creando una extensión:
 
       public static void CloseExt(this SvcClient proxy)
       {
          if (proxy != null)
          {
              var checkClosedState =
                  CommunicationState.Closed | CommunicationState.Closing;
 
              if (proxy.State == CommunicationState.Faulted)
              {
                  proxy.Abort();
              }
              else if (proxy.State != checkClosedState)
              {
                  proxy.Close();
              }
          }
      }
 
Y para utilizar la extensión el código se modificaría a:
 
         SvcClient proxy = null;
 
        try
        {
           proxy = ProxyFactory.ObtenerProxy;
 
           //Utilizar el proxy
        }
        catch (Exception)
        {
            throw;
        }
        finally
        {
            proxy.CloseExt();
        }
 
De esta manera siempre se llama a la extensión CloseExt(), la que se encarga de cerrar o abortar el proxy según su estado, impidiendo que se genere una excepción por intentar cerrar un proxy en estado “Faulted”.

 

 

Tags:

WCF

Acerca de los Autores

Este es el blog del equipo de VEMN SA 
Presentaremos temas que nos parezcan de interés sobre tecnología .NET, Procesos y Metodologías y todo aquello relacionado con el proceso de desarrollo de Software

Month List

BlogRoll

Download OPML file OPML