Pregunta Entity Framework 5 Actualización de un registro


He estado explorando diferentes métodos de edición / actualización de un registro dentro de Entity Framework 5 en un entorno ASP.NET MVC3, pero hasta ahora ninguno de ellos marca todas las casillas que necesito. Explicaré por qué.

He encontrado tres métodos a los cuales mencionaré los pros y los contras:

Método 1 - Cargar registro original, actualizar cada propiedad

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    original.BusinessEntityId = updatedUser.BusinessEntityId;
    original.Email = updatedUser.Email;
    original.EmployeeId = updatedUser.EmployeeId;
    original.Forename = updatedUser.Forename;
    original.Surname = updatedUser.Surname;
    original.Telephone = updatedUser.Telephone;
    original.Title = updatedUser.Title;
    original.Fax = updatedUser.Fax;
    original.ASPNetUserId = updatedUser.ASPNetUserId;
    db.SaveChanges();
}    

Pros

  • Puede especificar qué propiedades cambian
  • Las vistas no necesitan contener todas las propiedades

Contras

  • 2 consultas en la base de datos para cargar el original y luego actualizarlo

Método 2 - Cargar registro original, establecer valores modificados

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    db.Entry(original).CurrentValues.SetValues(updatedUser);
    db.SaveChanges();
}

Pros

  • Solo las propiedades modificadas se envían a la base de datos

Contras

  • Las vistas deben contener todas las propiedades
  • 2 consultas en la base de datos para cargar el original y luego actualizarlo

Método 3: adjunte el registro actualizado y establezca el estado en EntityState.Modified

db.Users.Attach(updatedUser);
db.Entry(updatedUser).State = EntityState.Modified;
db.SaveChanges();

Pros

  • 1 x consulta en la base de datos para actualizar

Contras

  • No se puede especificar qué propiedades cambian
  • Las vistas deben contener todas las propiedades

Pregunta

Mi pregunta para ustedes chicos; ¿Hay alguna forma limpia de lograr este conjunto de objetivos?

  • Puede especificar qué propiedades cambian
  • Las vistas no necesitan contener todas las propiedades (¡como la contraseña!)
  • 1 x consulta en la base de datos para actualizar

Entiendo que esto es algo menor de señalar, pero me puede faltar una solución simple para esto. Si no, el método uno prevalecerá ;-)


811
2018-03-11 10:27


origen


Respuestas:


Estás buscando:

db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.Property(e => e.Email).IsModified = true;
// other changed properties
db.SaveChanges();

645
2018-03-11 13:12



Realmente me gusta la respuesta aceptada. Creo que hay otra manera de abordar esto también. Supongamos que tiene una lista muy corta de propiedades que no desea incluir en una vista, por lo que cuando actualice la entidad, se omitirán. Digamos que esos dos campos son Contraseña y SSN.

db.Users.Attach(updatedUser);

var entry = db.Entry(updatedUser);
entry.State = EntityState.Modified;

entry.Property(e => e.Password).IsModified = false;
entry.Property(e => e.SSN).IsModified = false;   

db.SaveChanges();   

Este ejemplo le permite esencialmente dejar su lógica comercial sola después de agregar un nuevo campo a su tabla de Usuarios y a su Vista.


168
2017-08-01 21:01



foreach(PropertyInfo propertyInfo in original.GetType().GetProperties()) {
    if (propertyInfo.GetValue(updatedUser, null) == null)
        propertyInfo.SetValue(updatedUser, propertyInfo.GetValue(original, null), null);
}
db.Entry(original).CurrentValues.SetValues(updatedUser);
db.SaveChanges();

27
2017-11-12 11:33



He agregado un método de actualización extra en mi clase base de repositorio que es similar al método de actualización generado por Scaffolding. En lugar de configurar el objeto completo como "modificado", establece un conjunto de propiedades individuales. (T es un parámetro genérico de clase).

public void Update(T obj, params Expression<Func<T, object>>[] propertiesToUpdate)
{
    Context.Set<T>().Attach(obj);

    foreach (var p in propertiesToUpdate)
    {
        Context.Entry(obj).Property(p).IsModified = true;
    }
}

Y luego llamar, por ejemplo:

public void UpdatePasswordAndEmail(long userId, string password, string email)
{
    var user = new User {UserId = userId, Password = password, Email = email};

    Update(user, u => u.Password, u => u.Email);

    Save();
}

Me gusta un viaje a la base de datos. Sin embargo, es mejor hacer esto con modelos de vista, para evitar repetir conjuntos de propiedades. No he hecho eso todavía porque no sé cómo evitar llevar los mensajes de validación en mis validadores de modelos de vista a mi proyecto de dominio.


21
2018-04-25 16:19



public interface IRepository
{
    void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class;
}

public class Repository : DbContext, IRepository
{
    public void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class
    {
        Set<T>().Attach(obj);
        propertiesToUpdate.ToList().ForEach(p => Entry(obj).Property(p).IsModified = true);
        SaveChanges();
    }
}

7
2018-03-16 16:04



Solo para agregar a la lista de opciones. También puede tomar el objeto de la base de datos y usar una herramienta de asignación automática como Auto Mapper  para actualizar las partes del registro que desea cambiar ...


2
2017-12-03 15:58



Dependiendo de su caso de uso, se aplican todas las soluciones anteriores. Así es como lo hago generalmente sin embargo:

Para el código del lado del servidor (por ejemplo, un proceso por lotes), generalmente cargo las entidades y trabajo con proxies dinámicos. Por lo general, en procesos por lotes, debe cargar los datos de todos modos en el momento en que se ejecuta el servicio. Intento cargar por lotes los datos en lugar de usar el método find para ahorrar algo de tiempo. Dependiendo del proceso, utilizo un control de concurrencia optimista o pesimista (siempre utilizo optimismo, excepto en los escenarios de ejecución paralelos donde necesito bloquear algunos registros con sentencias SQL simples, aunque esto es raro). Dependiendo del código y el escenario, el impacto puede reducirse a casi cero.

Para los escenarios del lado del cliente, tiene algunas opciones

  1. Use modelos de vista. Los modelos deben tener una propiedad UpdateStatus (no modificado-insertado-actualizado-eliminado). Es responsabilidad del cliente establecer el valor correcto para esta columna en función de las acciones del usuario (insert-update-delete). El servidor puede consultar el archivo db para obtener los valores originales o el cliente debe enviar los valores originales al servidor junto con las filas modificadas. El servidor debe adjuntar los valores originales y usar la columna UpdateStatus para cada fila para decidir cómo manejar los nuevos valores. En este escenario siempre uso concurrencia optimista. Esto solo hará las instrucciones de inserción, actualización, eliminación y no selecciones, pero puede necesitar algún código inteligente para recorrer el gráfico y actualizar las entidades (depende de su escenario - aplicación). Un mapeador puede ayudar, pero no maneja la lógica CRUD

  2. Use una biblioteca como breeze.js que oculte la mayor parte de esta complejidad (como se describe en 1) e intente adaptarla a su caso de uso.

Espero eso ayude


1
2018-05-30 12:07