这是我使用 EF 的情况。
Repository 获取 A 的实例并返回到表示层(即 MVC 控制器)
控制器更改 A 实例上的某些属性并将其返回以保持不变。
在坚持之前,我需要弄清楚对对象做了什么更改并验证是否允许更改。
为了比较更改,我需要数据库中的旧实例。
但是 EF 返回相同的脏实例,所以我无法比较它们。
我尝试做的事情:类结构
public Class A {
public B B {get;set;}
}
public class B {
public ICollection<A> As {get;set;}
public C c { get; set;}
}
public class C {
}
B 和 C 映射到同一个数据库表。
虽然这是因为 EF 正在跟踪旧实例,并且由于尚未在实例上调用 save,所以它返回相同的 inatce。
所以我关闭了延迟加载、代理生成,并将对象作为存储库的不可跟踪返回。
现在 EF 从数据库返回新记录,但是如果更改了 A 上的某些属性,那么在 B 的 A 集合中,它只加载我更改的 A 的实例,而不是整个集合。
当我想创建一个新的 A 并保存时,我执行以下操作
B b = GetSomeOldB(); A a = 新 A(); aB = b a.Save();
所以我基本上将新的 A 添加到上下文中并调用 SaveChanges。
Ef 返回“无法将 C 转换为 B”的异常。
基本上,我想要的只是当我要求时从上下文中获取旧的对象图,与脏的比较,让脏的坚持下去。
非常感谢任何帮助!
这是最终实现的解决方案: 1. 重新启用跟踪和代理创建 2. 从 EF 获取原始副本。3. 编写了这个通用方法来水合实体的一个新实例
public ICollection<T> GetOriginalCollection<T>(ICollection<T> changedCollection) where T : class {
ICollection<T> original = new Collection<T>();
foreach (var item in changedCollection) {
//Dont return the newly added ones to the original collection
if (_context.Entry(item).State != EntityState.Added){
original.Add(GetOriginal(item));
}
}
return original;
}
public T GetOriginal<T>(T changedEntity) where T : class {
Func<DbPropertyValues, Type, object> getOriginal = null;
getOriginal = (originalValues, type) =>
{
object original = Activator.CreateInstance(type, true);
foreach (var ptyName in originalValues.PropertyNames) {
var property = type.GetProperty(ptyName);
object value = originalValues[ptyName];
//nested complex object
if (value is DbPropertyValues) {
property.SetValue(original, getOriginal(value as DbPropertyValues, property.PropertyType));
} else{
property.SetValue(original, value);
}
}
return original;
};
return (T)getOriginal(_context.Entry(changedEntity).OriginalValues, typeof(T));
}