Pequeños detalles sobre Entity Framework (2ª parte)

23. July 2011 13:27 by Oscar.SS in Desarrollo Empresarial  //  Tags:   //   Comments (0)

En el primer artículo de esta serie vimos una serie de comportamientos muy elementales a la hora de trabajar con el contexto de Entity Framework. Ahora vamos a complicar la cosa un poco. En realidad, como sucede muchas veces, será más complicado para el que lo intenta explicar que para el que lo entiende  ;-)

Estado del contexto entre capas

Supongamos por un momento que estamos trabajando en una aplicación N-Layer. Una de las funcionalidades de nuestra aplicación es permitir que el usuario modifique los datos de un Cliente existente (ver Modelo EF del ejemplo anterior) y luego poder salvar los cambios efectuados.

Como una imagen vale más que mil palabras, veamos nuestra arquitectura (imagen de la derecha) como siempre simplificada para el ejemplo que nos ocupa.

La pregunta que debemos hacernos es que ocurre con nuestra entidad Cliente cuando el objeto es serializado por el servico WCF para ser enviado a la capa de interfaz de usuario. Lo que sucede es que el objeto es deserializado al ser recibido en la UI para su consumo, lógicamente ya no se encuentra adjuntado al contexto de EF.

Es decir, del servicio WCF para arriba el contexto EF es totalmente ciego. Por lo tanto, aunque nosotros estemos trabajando con una entidad de tipo Cliente en la UI, el contexto EF no tiene conocimiento de esta entidad y por lo tanto no se entera si realizamos cambios sobre ella.

Nota: Que nadie se lleve a engaño, aunque no viajáramos a través de un servicio WCF, el problema seguiría existiendo. Es decir, cuando recibamos los campos modificados por el usuario en la UI naturalmente trataremos de instanciar un nuevo objeto Cliente y volcar estos cambios, pero antes deberemos adjuntar nuestra entidad Cliente al contexto de EF.

 

Volviendo a nuestra arquitectura donde si teníamos un servicio WCF, vamos acompañar a nuestra entidad Cliente en su viaje de ida desde la base de datos, pasando por todas las capas hasta la UI, y vuelta a la base de datos para guardar los cambios efectuados.

 

Paso 1. Accedemos a la base de datos

Desde nuestra capa de negocio, y obviando repositorios y otras capas intermedias, accedemos a la base de datos para obtener la entidad Cliente que se quiere modificar.

        public static Cliente ObtenerClientePorId(int id)
        {
            var dataContex 
= new BooksDBModelContainer();

            
var cliente dataContex.Clientes.FirstOrDefault(c => c.ClienteId == id);

            return 
cliente;
        
}

 Si incluimos un punto de interrupción al ejecutar el código podemos comprobar la propiedad EntityState de nuestra entidad Cliente.

 

 

El estado de la entidad está establecido a Unchanged lo que significa que nuestra entedidad Cliente está en el contexto de EF y no se han realizado modificaciones sobre ella desde que se adjunto al contexto.

 

Paso 2. El servicio WCF recibe la entidad

En el código del nuestro servicio WCF realizamos la llamada a la capa de negocio para obtener la entidad Cliente.

        public Cliente ObtenerCliente(int id)
        {
            var cliente 
ServicioClientes.ObtenerClientePorId(id);

            return 
cliente;
        
}

Veamos que valor tiene la propiedad StateEntity de la entidad Cliente en este momento.

Como podemos comprobar su estado no ha sido modificado y sigue adjuntada al contexto de EF. Esto es porque aún el objeto no ha sido serializado para enviarse a la capa de interfaz.

 

Paso 3. En la UI el objeto es deserializado

Cuando el Cliente llega a nuestra capa UI es deserializado para su consumo.

            using (var wcf = new ServicioWcf.ServicioWcfClient())
            {
                var cliente 
wcf.ObtenerCliente(id);

                return 
View(cliente);
            
}

Como hemos comentado anteriormente, la entidad devuelta por el servicio WCF ya no pertenece a nuestro contexto EF. Veamos.

Como se puede apreciar la propiedad EntityState de ha establecido a Detached. Por lo tanto a partir de aquí, nuestro contexto EF, desconoce que hacemos con esta entidad Cliente.

 

Paso 4. En la UI se recibe el Cliente modificado

Después de que la interfaz de usuario se ha renderizado y el usuario a modificado, por ejemplo la dirección de nuestro Cliente, el objeto es "armado" con los nuevos valores para enviarlo de nuevo a la base de datos.

            using (var wcf = new ServicioWcf.ServicioWcfClient())
            {
                var clienteModificado 
wcf.ModificarCliente(cliente);

                return 
View("Detalles", clienteModificado);
            
}

Como de momento no hemos adjuntado ni actualizado las modificaciones del Cliente es de suponer, y creerme que así es, que su estado sigue siendo Detached cuando es enviado al servicio WCF.

 

Paso 5. El servicio WCF recibe las modificaciones

En realidad el servicio WCF recibe una entidad Cliente con la modificaciones realizadas pero sigue sin estar adjuntado al contexto de EF.

        public Cliente ModificarCliente(Cliente cliente)
        {
            var clienteModificado 
ServicioClientes.ActualizarCliente(cliente);

            return 
clienteModificado;
        
}

Comprobemos con que estado llega el Cliente al servicio WCF antes de ser serializado para enviarlo a la capa de negocio.

 

Paso 6. La lógica de negocio recibe las modificaciones

Lógicamente si desde el servicio WCF enviamos una entidad Cliente con la modificaciones y no pertenecía al contexto de EF, a nuestra capa de negocio llegará una entidad Cliente con el mismo estado. Es aquí donde debemos hacer nosotros el trabajo de añadirlo al contexto de EF.

        public static Cliente ActualizarCliente(Cliente cliente)
        {
            var dataContex 
= new BooksDBModelContainer();

            
//Creamos un nuevo objeto Cliente que almacenará los cambios efectuados en UI
            
var clienteModificado = new Cliente
                                        {
                                            ClienteId 
cliente.ClienteId  // clienteModificado tiene el estado Detached
                                        
};

            
//Adjuntamos el nuevo Cliente al contexto EF
            
dataContex.Clientes.Attach(clienteModificado);  // clienteModificado tiene el estado Unchanged

            //Le asignamos los cambios de los valores obtenidos desde la UI
            
dataContex.Clientes.ApplyCurrentValues(cliente);

            
//Actualizamos el registro en la base de datos
            
dataContex.SaveChanges();

            return 
clienteModificado;
        
}

Bueno, como he incluido comentarios en el código me voy ahorrar algunas explicaciones, simplemente vamos a comprobar que estado tiene la instancia clienteModificado justo antes de enviar los cambios a la base de datos.

Después de volcar los cambios, de la entidad Cliente que llegaba desde el servico WCF, a la nueva instancia clienteModificado, Entity Framework detecta estos cambios y marca esta entidad como Modified. Todas la entidades marcadas como modificadas serán actualizadas en la base de datos al ejecutar el método SaveChanges().

Recent Comments

Comment RSS

Month List