entity-framework - update - migraciones entity framework
ValidaciĆ³n del Entity Framework con actualizaciones parciales. (3)
Estoy utilizando Entity Framework 5.0 con las entidades DbContext y POCO. Hay una entidad simple que contiene 3 propiedades:
public class Record
{
public int Id { get; set; }
public string Title { get; set; }
public bool IsActive { get; set; }
}
El campo Título siempre está sin modificar, y la interfaz de usuario simplemente lo muestra sin proporcionar ningún cuadro de entrada para modificarlo. Es por eso que el campo Title
se establece en null
cuando el formulario se envía al servidor.
Así es como le digo a EF que realice una actualización parcial de la entidad ( IsActive
campo IsActive
):
public class EFRepository<TEntity>
{
...
public void PartialUpdate(TEntity entity, params Expression<Func<TEntity, object>>[] propsToUpdate)
{
dbSet.Attach(entity);
var entry = _dbContext.Entry(entity);
foreach(var prop in propsToUpdate)
contextEntry.Property(prop).IsModified = true;
}
}
y la llamada:
repository.PartialUpdate(updatedRecord, r => r.IsActive);
Al SaveChanges
método SaveChanges
, obtengo la DbEntityValidationException
, que me dice que se requiere el Title
. Cuando configuro dbContext.Configuration.ValidateOnSaveEnabled = false
, todo está bien. ¿Hay alguna manera de evitar deshabilitar la validación en todo el contexto y decirle a EF que no valide las propiedades que no se están actualizando? Gracias por adelantado.
En referencia a la respuesta de Ladislav , agregué esto a la clase DbContext
, y ahora elimina todas las propiedades que no están modificadas.
Sé que no se omite por completo la validación de esas propiedades, sino que simplemente se la omite, pero EF valida por entidad y no por propiedad, y reescribir todo el proceso de validación de nuevo fue demasiado complicado para mí.
protected override DbEntityValidationResult ValidateEntity(
DbEntityEntry entityEntry,
IDictionary<object, object> items)
{
var result = base.ValidateEntity(entityEntry, items);
var falseErrors = result.ValidationErrors
.Where(error =>
{
if (entityEntry.State != EntityState.Modified) return false;
var member = entityEntry.Member(error.PropertyName);
var property = member as DbPropertyEntry;
if (property != null)
return !property.IsModified;
else
return false;//not false err;
});
foreach (var error in falseErrors.ToArray())
result.ValidationErrors.Remove(error);
return result;
}
Este es un remix de la respuesta anterior de @Shimmy y es una versión que actualmente uso.
Lo que he agregado es la cláusula (entityEntry.State != EntityState.Modified) return false;
en el Where
:
protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<object, object> items)
{
var result = base.ValidateEntity(entityEntry, items);
var falseErrors = result
.ValidationErrors
.Where(error =>
{
if (entityEntry.State != EntityState.Modified) return false;
var member = entityEntry.Member(error.PropertyName);
var property = member as DbPropertyEntry;
if (property != null) return !property.IsModified;
return false;
});
foreach (var error in falseErrors.ToArray())
{
result.ValidationErrors.Remove(error);
}
return result;
}
Si usa actualizaciones parciales o entidades de código auxiliar (¡ambos enfoques son bastante válidos!) No puede usar la validación de EF global porque no respeta sus cambios parciales ; siempre valida la entidad completa. Con la lógica de validación predeterminada, debe desactivarlo llamando al mencionado:
dbContext.Configuration.ValidateOnSaveEnabled = false
Y validar cada propiedad actualizada por separado. Esperemos que esto haga la magia, pero no lo probé porque no uso la validación de EF:
foreach(var prop in propsToUpdate) {
var errors = contextEntry.Property(prop).GetValidationErrors();
if (erros.Count == 0) {
contextEntry.Property(prop).IsModified = true;
} else {
...
}
}
Si desea ir un paso más allá, puede intentar anular ValidateEntity
en su contexto y reimplementar la validación de la forma en que valida la entidad completa o solo las propiedades seleccionadas según el estado de la entidad y el estado de las propiedades de IsModified
, que le permitirá utilizar la validación de EF con Actualizaciones parciales y entidades de stub.
La validación en EF es un concepto IMHO equivocado: introduce lógica adicional en la capa de acceso a datos a la que no pertenece la lógica. Se basa principalmente en la idea de que siempre trabaja con entidades enteras o incluso con gráficos de entidades completas si coloca las reglas de validación requeridas en las propiedades de navegación. Una vez que viole este enfoque, siempre encontrará que un único conjunto fijo de reglas de validación codificadas para sus entidades no es suficiente.
Una de las cosas que tengo en mi muy largo trabajo pendiente es investigar cómo afecta la validación a la velocidad de la operación de SaveChanges
: solía tener mi propia API de validación en EF4 (antes de EF4.1) basada en DataAnnotations y su clase Validator
y dejé de usarla Muy pronto debido a un rendimiento muy pobre.
La solución con el uso de SQL nativo tiene el mismo efecto que usar entidades de apéndice o actualizaciones parciales con la validación desactivada = sus entidades aún no están validadas pero, además, sus cambios no forman parte de la misma unidad de trabajo.