Entity Framework (V): Enlazado y desenlazado de entidades. Estados


Una vez que tenemos claro que un DbContext es el encargado de velar por la integridad en el esquema objeto-relacional, ¿qué ocurriría si manejamos objetos que, por alguna razón, escapan a su control? Nos referimos, por ejemplo, al envío de los datos de un cliente a través de un formulario web y ponernos a la espera de que el usuario los modifique en otra página distinta. Este escenario implicaría, con toda seguridad, que el DbContext en el que se recuperó el objeto sea distinto al DbContext que se encargará de modificarlo.

Por lo tanto, tendremos dos opciones a la hora de tratar este problema:

  • Volver a recuperar el objeto completo, copiar todos los datos del objeto enviado por el usuario al objeto que acabamos de recuperar y guardar los cambios.
  • Enlazar directamente el objeto al DbContext y decirle que actualice los cambios.

Para la primera opción no es necesaria mucha explicación, puesto que se trata de una modificación normal y corriente. Para la segunda opción habrá que trabajar un poco más, pero se considera una opción más correcta. Además, el proceso dependerá de si estamos haciendo uso de un ObjectContext (versión anterior a 4.1) o un DbContext (versión posterior a ésta).

Enlazado en Entity Framework 4.0

Empezaremos explicando cómo se realizaría esta operación con un ObjectContext.


           Cliente datosAntiguos = null;

           // Instanciamos el DbContext
           using(var objectContext = new testdbObjectContext())
           {
               // Recuperamos el cliente anterior
               datosAntiguos = objectContext.Clientes.Where(cliente => cliente.IdCliente == 3).First();
           }

Tenemos los datos de un cliente almacenados en datosAntiguos. Como podemos comprobar, al finalizar el using nuestro contexto habrá muerto, por lo que el objeto datosAntiguos estará libre. Esos serán los datos que se le remitirán al cliente.

Ahora imaginemos que el cliente recibe esos datos y modifica los campos Nombre y FechaNacimiento, y los recibimos en un objeto llamado datosNuevos. Simularemos esto creando nosotros el registro y cambiándole manualmente los datos. Recordemos que el identificador debe ser el mismo que tenía previamente.


            using (var objectContext = new testdbObjectContext ())
            {
                // Creamos un nuevo cliente con el MISMO ID que el anterior y
                // cambiamos algunos datos
                Cliente datosNuevos = new Cliente()
                {
                    IdCliente = datosAntiguos.IdCliente,
                    Nombre = "Ana Maria Lopez Diaz",
                    FechaNacimiento = new DateTime(1947, 1, 15)
                };

                // Añadimos el cliente anterior al contexto para informarle que queremos
                // enlazar el objeto.
                objectContext.Attach(datosAntiguos);

                // Actualizamos el cliente mediante el método ApplyPropertyChanges
                objectContext.ApplyPropertyChanges("Cliente", datosNuevos);
                objectContext.SaveChanges();
            }

El método Attach indica a nuestro context que “empiece a preocuparse” por el destino del objeto que le hemos pasado como parámetro. Por lo tanto, cualquier cambio realizado sobre este objeto será ahora repercutido sobre la fuente de datos al invocar el método SaveChanges().

Al invocar ApplyPropertyChanges y pasarle el objeto con los nuevos datos, Entity Framework ya sabrá, gracias a que el identificador de ambos elementos coincide, que los datos de ese registro deben ser actualizados.

Una vez invocado SaveChanges(), los cambios son aplicados.

Enlazado en Entity Framework 4.1+

A partir de esta versión, este proceso se simplifica bastante. Bastará con realizar lo siguiente:


            // Instanciamos un nuevo DbContext. El objeto clienteAnterior ya no tiene ninguna relación
            // con el contexto, ya que éste ha muerto en el bloque anterior.
            // Cualquier cambio sobre este objeto no será ya reflejado en la base de datos
            using (var dbContext = new testdbEntities())
            {

                // Creamos un nuevo cliente con el MISMO ID que el anterior y
                // cambiamos algunos datos
                Cliente datosNuevos = new Cliente()
                {
                    IdCliente = 3,
                    Nombre = "Ana Maria Lopez Diaz",
                    FechaNacimiento = new DateTime(1947, 1, 15)
                };

                // Añadimos el cliente anterior al contexto para informarle que queremos
                // enlazar el objeto.
                dbContext.Clientes.Attach(datosNuevos);

                // Cambiamos el estado a "Modificado" para que Entity Framework sepa que
                // deben actualizarse los datos
                dbContext.Entry(datosNuevos).State = System.Data.EntityState.Modified;
                dbContext.SaveChanges();
            }

Si nos fijamos bien, en la versión 4.1 nos hemos limitado a enlazar el nuevo objeto al listado en lugar de al contexto, y hemos cambiado manualmente el estado de la entidad para forzar su actualización. Al ejecutar SaveChanges(), el contexto comprobará los estados de todas sus entidades y aplicará la operación correspondiente a cada una. En nuestro caso, actualizando sus datos.

El método opuesto a Attach() es Detach() y, como su propio nombre indica, hace que el contexto deje de trazar los cambios realizados sobre ese objeto, ignorándolo cuando se ejecute un SaveChanges().

Estados de una entidad

Para finalizar, hablaremos de los posibles estados de una entidad. Según el Intellisense, podemos observar los siguientes estados:

Estos estados son:

  • Added: la entidad se añadirá a la lista. Se ejecutará una sentencia insert sobre la base de datos.
  • Deleted: la entidad se eliminará. Se ejecutará una sentencia delete sobre la base de datos.
  • Detached: la entidad no será tenida en cuenta a la hora de aplicar cambios.
  • Modified: la entidad ha modificado alguno de sus valores. Se ejecutará una sentencia update sobre la base de datos.
  • Unchanged: la entidad no ha sufrido cambios desde que se recuperó de la fuente de datos.

Sabiendo esto, podemos jugar un poco con las propiedades y realizar operaciones de forma “alternativa”, tal y como hemos hecho con la actualización. Así, una forma de insertar un nuevo cliente podría ser la siguiente:


            Cliente guillermoSanabria = new Cliente()
            {
                Nombre = "Guillermo Sanabria San Juan",
                FechaNacimiento = new DateTime(1983, 11, 1)
            };
            // Cambiamos el estado de la entidad a Added
            dbContext.Entry(guillermoSanabria).State = EntityState.Added;

            // Guardamos los cambios
            dbContext.SaveChanges();

Esto provocará que la entidad se inserte en la base de datos.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s