5

He enfrentado situaciones en las que necesito tener EF readonly property en caso de 'actualización optimista' (no carga el estado actual de su dominio desde la base de datos para verificar qué propiedades realmente han cambiado. Simplemente establece su objeto como Modificado y lo actualiza a la base de datos. En este caso, evita las operaciones redundantes de selección y fusión.Propiedades de solo lectura en EF 4.1

No puede escribir algo como esto: DataContext.Entry(entity).Property(propertyName).IsModified = false;, porque el valor 'falso' no es compatible y obtendrá una excepción. (en EF 4.1)

He creado una estructura simple para registrar propiedades de solo lectura en el repositorio. Por lo tanto, puede facilitar la modificación de propiedades que simplemente no son leales.

¿Qué opina sobre esto?

public abstract class RepositoryBase<T> where T : class 
{ 
private const string MethodReferenceErrorFormat = "Expression '{0}' refers to a method, not a property."; 
private const string FieldReferenceErrorFormat = "Expression '{0}' refers to a field, not a property."; 

protected IList<PropertyInfo> _readOnlyProperties; 
     /// <summary> 
     /// This method is used to register readonly property for Entity. 
     /// </summary> 
     /// <param name="propertyLambda">Entity property as LambdaExpression</param> 
     protected void RegisterReadOnlyProperty<TProperty>(Expression<Func<T, TProperty>> propertyLambda) 
     { 
      Guard.ArgumentNotNull(propertyLambda, "propertyLambda"); 

      var propertyMember = propertyLambda.Body as MemberExpression; 
      if (propertyMember == null) 
      { 
       var exceptionMessage = string.Format(MethodReferenceErrorFormat, propertyLambda); 
       throw new ArgumentException(exceptionMessage); 
      } 

      var propertyInfo = propertyMember.Member as PropertyInfo; 
      if (propertyInfo == null) 
      { 
       var exceptionMessage = string.Format(FieldReferenceErrorFormat, propertyLambda); 
       throw new ArgumentException(exceptionMessage); 
      } 

      _readOnlyProperties.Add(propertyInfo); 
     } 

     /// <summary> 
     /// This method is used to attach domain object to DbContext and mark it as modified to save changes. 
     /// </summary> 
     /// <param name="entity">Detached entity</param> 
     public void SetModified(T entity) 
     { 
      Guard.ArgumentNotNull(entity, "entity"); 

      //Mark whole entity as Modified, when collection of readonly properties is empty. 
      if(_readOnlyProperties.Count == 0) 
      { 
       DataContext.Entry(entity).State = EntityState.Modified; 
       return; 
      } 

      //Attach entity to DbContext. 
      _dbSet.Attach(entity); 

      //Mark all properties except readonly as Modified. 
      var allProperties = entity.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); 
      var propertiesForUpdate = allProperties.Except(_readOnlyProperties); 
      foreach (var propertyInfo in propertiesForUpdate) 
      { 
       DataContext.Entry(entity).Property(propertyInfo.Name).IsModified = true; 
      } 
     } 

Respuesta

16

Esto funcionaría, pero no me gusta la necesidad de registrar propiedades modificadas directamente en el repositorio. Puede olvidarse de las propiedades registradas y el código accidentalmente no guardará algunos cambios; será un error que será difícil de encontrar al reutilizar el repositorio en escenarios complejos. Me gusta la definición explícita de propiedades actualizadas cada vez que llamas algo así como Actualizar en tu repositorio. Además, no me gusta la reflexión en el código. A menos que modifiques tu código para obtener datos reflejados sobre cada entidad solo una vez para toda la aplicación, lo estás haciendo mal.

escribí el answer for EFv4 pero puede ser fácilmente modificado para EFv4.1:

public void Update(T entity, params Expression<Func<T, object>>[] properties) 
{ 
    _dbSet.Attach(entity); 
    DbEntityEntry<T> entry = _context.Entry(entity); 
    foreach (var selector in properties) 
    { 
     entry.Property(selector).IsModified = true; 
    } 
} 

Va a llamar así:

repo.Update(entity, e => e.Name, e => e.Description); 
+0

Gracias! Tu versión se ve bien! – zonder

+0

Cuando uso esto me da el siguiente error, No puedo convertir la expresión Lambda a Tipo 'Expresión > []' porque no es un tipo de delegado –

Cuestiones relacionadas