我尝试使用通用方法来更新实体框架集合,一对多。我做了这个方法,但是我遇到了问题,当我尝试验证时,新集合中的元素是否已存在于旧集合中。如果存在,我必须更新它,而不是删除并再次添加它。
代码是这样的:
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)
我也尝试过:
var newItem = this.Set<TChildren>().Local.FirstOrDefault(x => x == originalItem);
但也不起作用,总是返回null。我必须得到相应的条目并且只更新它。
如果不可能,还有另一种更新集合的通用方法&#34;一对多&#34;?
答案 0 :(得分:2)
我做了它,比较我的收藏中的关键属性,正如Magnus建议的那样:
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”,但如果需要,它会返回所有键。