Trabajar con estados de entidad

En este tema se explica cómo agregar y adjuntar entidades a un contexto y cómo Entity Framework los procesa durante SaveChanges. Entity Framework se encarga del seguimiento del estado de las entidades mientras están conectados a un contexto, pero en escenarios desconectados o de N niveles, puede informar a EF en qué estado deben estar las entidades. Las técnicas que se muestran en este tema se aplican igualmente a los modelos creados con Code First y EF Designer.

Estados de entidades y SaveChanges

Una entidad puede estar en uno de los cinco estados definidos por la enumeración EntityState. Estos estados son:

  • Agregado: se está realizando el seguimiento de la entidad por el contexto, pero aún no existe en la base de datos.
  • Sin cambios: el contexto realiza el seguimiento de la entidad y existe en la base de datos y sus valores de propiedad no han cambiado de los valores de la base de datos.
  • Modificado: la entidad es seguida por el contexto y existe en la base de datos; algunos o todos sus valores de propiedad se han modificado.
  • Eliminado: el contexto realiza el seguimiento de la entidad y existe en la base de datos, pero se ha marcado para su eliminación de la base de datos la próxima vez que se invoque SaveChanges.
  • Separado: la entidad no está siendo seguida por el contexto.

SaveChanges realiza diferentes acciones para las entidades en distintos estados:

  • SaveChanges no modifica las entidades sin cambios. Las actualizaciones no se envían a la base de datos para las entidades en estado Sin cambios.
  • Las entidades agregadas se insertan en la base de datos y, a continuación, se convierten en Unchanged al devolver SaveChanges.
  • Las entidades modificadas se actualizan en la base de datos y luego se convierten en "Sin cambios" cuando SaveChanges termina su ejecución.
  • Las entidades eliminadas se eliminan de la base de datos y, a continuación, se desasocian del contexto.

En los ejemplos siguientes se muestran formas en las que se puede cambiar el estado de una entidad o un grafo de entidad.

Adición de una nueva entidad al contexto

Se puede agregar una nueva entidad al contexto llamando al método Add en DbSet. Esto coloca la entidad en el estado Agregado, lo que significa que se insertará en la base de datos la próxima vez que se llame a SaveChanges. Por ejemplo:

using (var context = new BloggingContext())
{
    var blog = new Blog { Name = "ADO.NET Blog" };
    context.Blogs.Add(blog);
    context.SaveChanges();
}

Otra manera de agregar una nueva entidad al contexto es cambiar su estado a Agregado. Por ejemplo:

using (var context = new BloggingContext())
{
    var blog = new Blog { Name = "ADO.NET Blog" };
    context.Entry(blog).State = EntityState.Added;
    context.SaveChanges();
}

Por último, puede agregar una nueva entidad al contexto enlazándola a otra entidad que ya está siendo rastreada. Esto podría ser agregando la nueva entidad a la propiedad de navegación de colección de otra entidad o estableciendo una propiedad de navegación de referencia de otra entidad para que apunte a la nueva entidad. Por ejemplo:

using (var context = new BloggingContext())
{
    // Add a new User by setting a reference from a tracked Blog
    var blog = context.Blogs.Find(1);
    blog.Owner = new User { UserName = "johndoe1987" };

    // Add a new Post by adding to the collection of a tracked Blog
    blog.Posts.Add(new Post { Name = "How to Add Entities" });

    context.SaveChanges();
}

Tenga en cuenta que, para todos estos ejemplos, si la entidad que se va a agregar tiene referencias a otras entidades que aún no se han realizado el seguimiento, estas nuevas entidades también se agregarán al contexto y se insertarán en la base de datos la próxima vez que se llame a SaveChanges.

Asociación de una entidad existente al contexto

Si tiene una entidad que sabe que ya existe en la base de datos, pero que actualmente no está siendo rastreada por el contexto, puede indicar al contexto que rastree la entidad mediante el método Attach en DbSet. La entidad estará en estado Sin cambios en el contexto. Por ejemplo:

var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };

using (var context = new BloggingContext())
{
    context.Blogs.Attach(existingBlog);

    // Do some more work...  

    context.SaveChanges();
}

Tenga en cuenta que no se realizará ningún cambio en la base de datos si se llama a SaveChanges sin realizar ninguna otra manipulación de la entidad adjunta. Esto se debe a que la entidad está en estado Sin cambios.

Otra manera de adjuntar una entidad existente al contexto es cambiar su estado a Sin cambios. Por ejemplo:

var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };

using (var context = new BloggingContext())
{
    context.Entry(existingBlog).State = EntityState.Unchanged;

    // Do some more work...  

    context.SaveChanges();
}

Tenga en cuenta que, para ambos ejemplos, si la entidad que se adjunta tiene referencias a otras entidades que aún no se han realizado el seguimiento, estas nuevas entidades también se asociarán al contexto en estado Sin cambios.

Asociación de una entidad existente pero modificada al contexto

Si ya tiene una entidad que sabe que ya existe en la base de datos, pero a la que se le pueden haber realizado cambios, puede indicar al contexto que asocie la entidad y establezca su estado en Modificado. Por ejemplo:

var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };

using (var context = new BloggingContext())
{
    context.Entry(existingBlog).State = EntityState.Modified;

    // Do some more work...  

    context.SaveChanges();
}

Al cambiar el estado a Modificado, todas las propiedades de la entidad se marcarán como modificadas y todos los valores de propiedad se enviarán a la base de datos cuando se llame a SaveChanges.

Tenga en cuenta que si la entidad que se va a adjuntar tiene referencias a otras entidades que aún no se están siguiendo, estas nuevas entidades se asociarán al contexto en estado sin cambios, no se modificarán automáticamente. Si tiene varias entidades que deben marcarse como Modificada, debe establecer el estado de cada una de estas entidades individualmente.

Cambio del estado de una entidad con seguimiento

Puede cambiar el estado de una entidad que ya está siendo rastreada estableciendo la propiedad State en su entrada. Por ejemplo:

var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" };

using (var context = new BloggingContext())
{
    context.Blogs.Attach(existingBlog);
    context.Entry(existingBlog).State = EntityState.Unchanged;

    // Do some more work...  

    context.SaveChanges();
}

Tenga en cuenta que llamar a Add o Attach para una entidad que ya está siendo rastreada también se puede usar para cambiar el estado de la entidad. Por ejemplo, llamar a Attach para una entidad que se encuentra actualmente en estado Agregado cambiará su estado a Sin cambios.

Insertar o actualizar el patrón

Un patrón común para algunas aplicaciones es agregar una entidad como nueva (lo que da como resultado una inserción de base de datos) o Adjuntar una entidad como existente y marcarla como modificada (lo que da lugar a una actualización de base de datos) en función del valor de la clave principal. Por ejemplo, cuando se usan claves principales de enteros generadas por la base de datos, es habitual tratar una entidad con una clave cero como nueva y una entidad con una clave distinta de cero como existente. Este patrón se puede lograr estableciendo el estado de la entidad en función de una comprobación del valor de la clave principal. Por ejemplo:

public void InsertOrUpdate(Blog blog)
{
    using (var context = new BloggingContext())
    {
        context.Entry(blog).State = blog.BlogId == 0 ?
                                   EntityState.Added :
                                   EntityState.Modified;

        context.SaveChanges();
    }
}

Tenga en cuenta que, al cambiar el estado a Modificado, todas las propiedades de la entidad se marcarán como modificadas y todos los valores de propiedad se enviarán a la base de datos cuando se llame a SaveChanges.