5

我遇到過情況,在'樂觀更新'的情況下需要EF只讀屬性(您不會從數據庫加載域對象的當前狀態以檢查哪些屬性真的發生更改。你只需將你的對象設置爲Modified,並將它更新到數據庫。在這種情況下,你避免了冗餘的選擇和合並操作)。EF 4.1中的只讀屬性

你不能寫這樣的:DataContext.Entry(entity).Property(propertyName).IsModified = false;,因爲'false'值的設置不被支持,你會得到一個異常。 (在EF 4.1中)

我創建了一個簡單的結構,用於在存儲庫中註冊只讀屬性。 因此,您可以輕鬆修改非讀取屬性。

您對此有何看法?

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; 
      } 
     } 

回答

16

這將工作,但我不喜歡需要直接在存儲庫中註冊修改後的屬性。您可以忘記註冊的屬性,代碼將意外地不保存一些更改 - 這將是在複雜場景中重複使用存儲庫時很難找到的錯誤。每次您在存儲庫中調用Update時,我都喜歡更新屬性的明確定義。我也不喜歡代碼中的反思。除非你修改你的代碼來獲取關於每個實體的反射數據,而只是整個應用程序一次,否則你做錯了。

我寫的answer for EFv4但它可以很容易地修改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; 
    } 
} 

你會這樣稱呼它:

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

謝謝!你的版本看起來不錯! – zonder 2011-04-21 21:30:44

+0

當我使用它時,它給了我下面的錯誤,無法將Lambda表達式轉換爲Type'Expression > []',因爲它不是委託類型 – 2013-05-16 08:01:06