我试图创建一个通用方法来从一个分离的对象更新一个Entity及其所有的集合属性。例如:
public class Parent{
public int Id { get; set; }
public string ParentProperty { get; set; }
public List<Child> Children1 { get; set; }
public List<Child> Children2 { get; set; }
}
public class Child{
public int Id { get; set; }
public string ChildProperty { get; set; }
}
所以,我的第一个意图是使用这样的东西:
Repository<Parent>.Update(parentObj);
在这个方法中有一个神奇的东西可以更新Parent属性,并将parentObj的Children列表与数据库中的当前值进行比较,并相应地添加/更新/删除它们,但这对于我对EF的了解太复杂了/ Reflection / Generic ......所以我尝试了另一种更简单的方法:
Repository<Parent>.Update(parentObj, parent => parent.Children1
parent => parent.Children2);
这种方法使用起来会有点困难,但仍然可以接受。但我认为第二个参数必须是params Expression<Func<TEntity, ICollection<TRelatedEntity>>>[] relatedEntities
我有问题指定多个TRelatedEntity。所以我的尝试是第三步,但没有成功......
现在我尝试调用一个方法来更新Parent和一系列更新Childreen的方法,如下所示:
Repository<Parent>.Update(parentObj);
Repository<Parent>.UpdateChild(parentObj, parent => parent.Id, parent => parent.Children1);
Repository<Parent>.UpdateChild(parentObj, parent => parent.Id, parent => parent.Children2);
代码:
public virtual void Update(TEntity entityToUpdate)
{
context.Entry(entityToUpdate).State = EntityState.Modified;
}
public virtual void UpdateChild<TRelatedEntity>(TEntity entityToUpdate, Func<TEntity, object> keySelector, Expression<Func<TEntity, ICollection<TRelatedEntity>>> relatedEntitySelector) where TRelatedEntity: class
{
var entityInDb = dbSet.Find(keySelector.Invoke(entityToUpdate));
var current = relatedEntitySelector.Compile().Invoke(entityToUpdate);
var original = relatedEntitySelector.Compile().Invoke(entityInDb);
foreach (var created in current.Except(original))
{
context.Set<TRelatedEntity>().Add(created);
}
foreach (var removed in original.Except(current))
{
context.Set<TRelatedEntity>().Remove(removed);
}
foreach (var updated in current.Intersect(original))
{
context.Entry(updated).State = EntityState.Modified;
}
context.Entry(entityInDb).State = EntityState.Detached;
}
第一个问题是获取原始值,因为当我调用dbSet.Find时,实体已经在上下文中(context.Entry(entityToUpdate).State = EntityState.Modified;
)。
所以我试图改变第一个孩子的命令:
Repository<Parent>.Update(parentObj);
Repository<Parent>.UpdateChild(parentObj, parent => parent.Id, parent => parent.Children1);
Repository<Parent>.UpdateChild(parentObj, parent => parent.Id, parent => parent.Children2);
现在我有错误:
存储更新,插入或删除语句会影响意外的行数(0)。自实体加载后,实体可能已被修改或删除。有关理解和处理乐观并发异常的信息,请参阅http://go.microsoft.com/fwlink/?LinkId=472540。
总之,第一种方式会很好,但我也会对第二种/第三种方式感到满意。
非常感谢
请,我需要一个原生解决方案或使用Automapper(我们已在项目中使用),因为我的客户不喜欢外部依赖,如果我们需要适应项目,比如使用Attached对象来更新他们的相关实体,因此评论中的GraphDiff不符合我们的需求(当我尝试安装测试包时,VS 2015 RC崩溃了)
答案 0 :(得分:1)
您是否考虑过从数据库中获取对象并使用AutoMapper修改所有属性值?
我的意思是:
var obj = GetObjectFromDB(...);
AutoMapObj(obj, modifiedObj);
SaveInDb();