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().