¿Cómo actualizar el registro usando el núcleo del marco de la entidad?

88

¿Cuál es el mejor enfoque para actualizar los datos de una tabla de base de datos en el núcleo de trabajo del marco de entidad?

  1. Recupere la fila de la tabla, haga los cambios y guarde
  2. Use la actualización de palabras clave en el contexto de la base de datos y maneje la excepción para el elemento que no existe

¿Cuáles son las características mejoradas que podemos usar en EF6?

Charith
fuente

Respuestas:

104

Para actualizar una entidad con Entity Framework Core, este es el proceso lógico:

  1. Crear instancia para DbContextclase
  2. Recuperar entidad por clave
  3. Realizar cambios en las propiedades de la entidad
  4. Guardar cambios

Update()método en DbContext:

Comienza a rastrear la entidad dada en el estado Modificado de modo que se actualizará en la base de datos cuando SaveChanges()se llame.

El método de actualización no guarda los cambios en la base de datos; en su lugar, establece estados para las entradas en la instancia de DbContext.

Entonces, podemos invocar el Update()método antes para guardar los cambios en la base de datos.

Asumiré algunas definiciones de objetos para responder a su pregunta:

  1. El nombre de la base de datos es Store

  2. El nombre de la tabla es Producto

Definición de clase de producto:

Definición de la clase DbContext:

Lógica para actualizar entidad:

H. Herzl
fuente
1
Gracias . Este es un buen ejemplo de cómo utilizar 2. Utilice Actualización de palabras clave en el contexto de la base de datos y maneje la excepción para el elemento que no existe. Estoy más interesado en seleccionar cuál usar como mejor práctica.
Charith
¿Por qué usó nullable int?para ProductID? ¿Se convierte en clave primaria opcional?
Estupidez artificial
8
De hecho, la línea context.Products.Update es redundante ya que la entidad será rastreada una vez que la recupere del contexto. Aquí hay una excelente descripción general de los diferentes enfoques: learnentityframeworkcore.com/dbcontext/modifying-data
Johan Maes
67

Según documentos de Microsoft :

El enfoque de lectura primero requiere una lectura de base de datos adicional y puede resultar en un código más complejo para manejar conflictos de concurrencia

Sin embargo, debe saber que el uso del método Update en DbContext marcará todos los campos como modificados y los incluirá todos en la consulta. Si desea actualizar un subconjunto de campos, debe usar el método Adjuntar y luego marcar el campo deseado como modificado manualmente.

Ehsan Mirsaeedi
fuente
31
Solo una pequeña edición, ahora hay una versión más fuertemente tipada de esta API: context.Entry(person).Property(p => p.Name).IsModified = true;
Guru Stron
2
También se puede hacer simplementecontext.Entry(person).State = EntityState.Modified;
Renan Coelho
1
¿Qué significa este context.Entry (persona) .State = EntityState.Modified; ¿media? Si modifico varios campos, ¿debo realizar cambios en esta línea?
user989988
2
Buen punto ehsan jan! ; D Además, si la entidad es actualizada por el usuario y no sabe / le importa qué campos se modifican, puede usar _context.Attach(person).State = EntityState.Modified; para indicar que esta entidad se actualizará en el método SaveChanges.
S.Serpooshan
Gran captura. Por lo tanto, esto requiere que el contexto "se quede", para que sepa sobre las entidades en el contexto. Acabo de probar esto ... y si intentas editar uno no existente, ¡da una excepción! :) Se produjeron uno o más errores. (Intenté actualizar o eliminar una entidad que no existe en la tienda.)
granadaCoder
31
public async Task<bool> Update(MyObject item)
{
    Context.Entry(await Context.MyDbSet.FirstOrDefaultAsync(x => x.Id == item.Id)).CurrentValues.SetValues(item);
    return (await Context.SaveChangesAsync()) > 0;
}
Shadam
fuente
Creo que este método funciona muy bien, pero creo que la publicación está abajo porque podría haber usado más contexto. pero me gusta!
Sr. Kraus
1
¡A mí también me gusta! @Señor. Krause, ¿no sería la publicación baja (hasta ahora) debido a que solo tiene unos días de antigüedad?
Wellspring
1
Recibo "Violación de la restricción PRIMARY KEY 'PK_Offer'. No se puede insertar una clave duplicada en el objeto 'dbo.Offer'." De esto.
Magnus Karlsson
8

Microsoft Docs nos ofrece dos enfoques.

Código de edición HttpPost recomendado : leer y actualizar

Esta es la misma forma antigua que solíamos hacer en versiones anteriores de Entity Framework. y esto es lo que Microsoft nos recomienda.

Ventajas

  • Evita la sobreimpresión
  • El seguimiento automático de cambios de EF establece la marca Modifieden los campos que se modifican mediante la entrada del formulario.

Código alternativo de edición de HttpPost: crear y adjuntar

una alternativa es adjuntar una entidad creada por el enlazador de modelos al contexto EF y marcarla como modificada.

Como se mencionó en la otra respuesta, el enfoque de lectura primero requiere una lectura adicional de la base de datos y puede resultar en un código más complejo para manejar conflictos de concurrencia.

Nipuna
fuente
8

Es super simple

using (var dbContext = new DbContextBuilder().BuildDbContext())
{
    dbContext.Update(entity);
    await dbContext.SaveChangesAsync();
}
Christian Findlay
fuente
2

Después de revisar todas las respuestas, pensé que agregaría dos opciones simples

  1. Si ya accedió al registro usando FirstOrDefault () con el seguimiento habilitado (sin usar la función .AsNoTracking (), ya que deshabilitará el seguimiento) y actualizó algunos campos, simplemente puede llamar a context.SaveChanges ()

  2. En otro caso, ha publicado la entidad en el servidor utilizando HtppPost o ha desactivado el seguimiento por alguna razón, entonces debe llamar a context.Update (entityName) antes que context.SaveChanges ()

La primera opción solo actualizará los campos que cambió, pero la segunda opción actualizará todos los campos de la base de datos, aunque ninguno de los valores de campo se actualizó realmente :)

Ikram Shah
fuente
0

Un enfoque más genérico

Para simplificar este enfoque se utiliza una interfaz "id"

public interface IGuidKey
{
    Guid Id { get; set; }
}

El método de ayuda

    public static void Modify<T>(this DbSet<T> set, Guid id, Action<T> func)
        where T : class, IGuidKey, new()
    {
        var target = new T
        {
            Id = id
        };
        var entry = set.Attach(target);
        func(target);
        foreach (var property in entry.Properties)
        {
            var original = property.OriginalValue;
            var current = property.CurrentValue;

            if (ReferenceEquals(original, current))
            {
                continue;
            }

            if (original == null)
            {
                property.IsModified = true;
                continue;
            }

            var propertyIsModified = !original.Equals(current);
            property.IsModified = propertyIsModified;
        }
    }

Uso

dbContext.Operations.Modify(id, x => { x.Title = "aaa"; });
Simón
fuente