2015-06-06 57 views
1

我試圖做一個通用的方法來更新實體框架的集合,一對多。我這樣做的方法,但我有一個問題,當我嘗試驗證,如果新的集合中的元素在舊的已經存在。如果存在,我必須更新它,而不是刪除並再次添加它。如何檢查是否收集兩個實體項是相同的

的代碼是這樣的:

public TEntity UpdateCollection<TEntity, TChildren>(myappContext dbContext, TEntity parentObject, Expression<Func<TEntity, 
      ICollection<TChildren>>> propertyExpression, ICollection<TChildren> objectChilren) where TEntity : class where TChildren : class 
     { 

      var parentEntityObject = dbContext.Entry<TEntity>(parentObject); 
      List<TChildren> originalChildrenData = parentEntityObject.Collection(propertyExpression).CurrentValue.ToList(); 

      // Updating or removing existing items 
      foreach (var originalItem in originalChildrenData) 
      { 
       // Where the problem is: If entry was just modified, i have to update. 
       var newItem = objectChilren.FirstOrDefault(x => x == originalItem); 
       if (newItem != null) 
       { 
        dbContext.Entry<TChildren>(originalItem).CurrentValues.SetValues(newItem); 
        dbContext.Entry<TChildren>(originalItem).State = System.Data.EntityState.Modified; 
       } 
       else 
       { 
        dbContext.Entry<TChildren>(originalItem).State = System.Data.EntityState.Deleted; 
       } 
      } 

      // Adding new items 
      foreach(var newItem in objectChilren.Except(originalChildrenData)){ 
       parentEntityObject.Collection(propertyExpression).CurrentValue.Add(newItem); 
      } 

      parentEntityObject.State = System.Data.EntityState.Modified; 
      return parentEntityObject.Entity; 
     } 

而是試圖檢查與:

var newItem = objectChilren.FirstOrDefault(x => x == originalItem); 
        if (newItem != null) 

我也tryed有:

var newItem = this.Set<TChildren>().Local.FirstOrDefault(x => x == originalItem); 

但也不起作用,總是返回null。我必須得到相應的條目並且只更新它。

如果這是不可能的,有更新集合「一對多」另一種通用的方式?

+0

嘗試比較的對象,而不是我假設沒有重載equals和GetHashKey對象本身的主鍵屬性。 – Magnus

+0

我也這麼認爲,但是如何知道哪些是鑰匙?並比較它們?它需要是通用的,所以我不能定義一個主鍵。我得找哪一個是主要的和比較後 –

+1

看到這個[實體框架4如何查找主鍵(http://stackoverflow.com/questions/2958921/entity-framework-4-how-to-find -the-主鍵) – Magnus

回答

2

我做到了,關鍵屬性從我收集的比較,如馬格努斯認爲,像這樣的:

public TEntity UpdateCollection<TEntity, TChildren>(myappContext dbContext, TEntity parentObject, Expression<Func<TEntity, 
      ICollection<TChildren>>> propertyExpression, ICollection<TChildren> objectChilren) where TEntity : class where TChildren : class 
     { 

      var parentEntityObject = dbContext.Entry<TEntity>(parentObject); 
      List<TChildren> originalChildrenData = parentEntityObject.Collection(propertyExpression).CurrentValue.ToList(); 

      // Get key name 
      var entityKeyName = GetKeyName(dbContext, originalChildrenData.Union(objectChilren).First()); 

      // Updating or removing existing items 
      foreach (var originalItem in originalChildrenData) 
      { 

       var originalValueKey = originalItem.GetType().GetProperty(entityKeyName).GetValue(originalItem, null); 
       var itemCompareExpression = GetCompareExpression<TChildren>(entityKeyName, originalValueKey); 

       // If entry was just modified, i have to update. 
       var newItem = objectChilren.FirstOrDefault(itemCompareExpression.Compile()); 
       if (newItem != null) 
       { 
        dbContext.Entry<TChildren>(originalItem).CurrentValues.SetValues(newItem); 
        dbContext.Entry<TChildren>(originalItem).State = System.Data.EntityState.Modified; 
        // Remove item, because only 'new items' will be added after this loop 
        objectChilren.Remove(newItem); 
       } 
       else 
       { 
        dbContext.Entry<TChildren>(originalItem).State = System.Data.EntityState.Deleted; 
       } 
      } 

      // Adding new items 
      foreach(var newItem in objectChilren) 
      { 
       parentEntityObject.Collection(propertyExpression).CurrentValue.Add(newItem); 
      } 

      parentEntityObject.State = System.Data.EntityState.Modified; 
      return parentEntityObject.Entity; 
     } 

方法叫:

public string GetKeyName<TEntity>(myappContext dbContext, TEntity entity) where TEntity : class 
     { 
      ObjectContext objectContext = ((IObjectContextAdapter)dbContext).ObjectContext; 
      ObjectSet<TEntity> set = objectContext.CreateObjectSet<TEntity>(); 
      return set.EntitySet.ElementType.KeyMembers.FirstOrDefault().Name; 
     } 

     public Expression<Func<TEntity, bool>> GetCompareExpression<TEntity>(string keyName, object value) where TEntity : class 
     { 
      var parameter = Expression.Parameter(typeof(TEntity), "x"); 
      var property = Expression.Property(parameter, keyName); 
      var method = property.Type.GetMethod("Equals", new[] { property.Type }); 
      var convertedValue = Convert.ChangeType(value, property.Type); 
      var expression = Expression.Call(property, method, Expression.Constant(convertedValue)); 

      return Expression.Lambda<Func<TEntity, bool>>(expression, parameter); 
     } 

正如我的所有實體只有一個鍵,我只是在「GetKeyName」上使用「First」,但如果需要,它將返回所有的鍵。