如何在实体框架、禁用延迟加载、禁用代理和实体不可跟踪的情况下保存对象图
本文关键字:实体 跟踪 对象图 保存 情况下 延迟加载 框架 代理 | 更新日期: 2023-09-27 18:35:42
这是我使用 EF 的情况。
-
存储库获取 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();a.B = ba.保存();
所以我基本上将新的 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));
}
我认为
你想要的是在一个断开连接的环境中工作。您可以附加断开连接的实体,并通过指定其实体状态来提供图形中的更改内容。如果你愿意,你可以创建像IObjectState这样的接口,并在你的模型中实现,以找出图中的确切变化。