我继承了一个带有数据库的Web应用程序,该数据库不会删除行(出于审计原因)而是有一个"已删除"选择或加入表时必须检查的标志。它被带到了Entity Framework 5,并且为了自动化这个系统,DbContext已被修改为类似下面的代码:
public class DbContext : System.Data.Entity.DbContext
{
public override int SaveChanges()
{
var deletedEntities = ChangeTracker.Entries().Where(x=>x.State == EntityState.Deleted).ToArray();
foreach(var entityEntry in deletedEntities)
{
try
{
dynamic entity = entityEntry.Entity;
entity.Deleted = true;
entityEntry.State = EntityState.Modified;
}
catch(RuntimeBinderException)
{
//allow hard delete
}
}
return base.SaveChanges();
}
}
实际代码更复杂,因为它还设置更新时间,更新用户,检测新对象并设置创建时间/用户等。
但是,当我们有对象具有与之关联的外键并且代码加载那些关联对象时,我们遇到了问题。引用已删除对象的FK将被删除。
EF代码处于数据库优先模式,因为数据库早在公司决定切换到实体框架之前就已存在,并且数据库的FK约束都是" ON DELETE NO ACTION",因此,如果FK遵循数据库的设计,我们就不会期望将FK设置为null。
我们理解实体框架并不想孤立它们,但现有设计要求它们保持不变。我们期望并要求(出于审计原因)外键继续指向"已删除" row(再次,常规查询过滤掉已删除的行)。其中一个原因是,如果客户打电话给我们关于"意外"删除一些东西,我们可以翻转旗帜,一切都会#34;只是工作"。我无法改变这种设计。
例如,采用此简化方案代码:
//FooBarContext derives from the above DbContext and was generated from a database using Database First
using(var context = new FoobarContext())
{
var foo = context.FOO.Find(fooId);
var bar = foo.Bar;
context.BAR.Remove(bar);
context.SaveChanges();
}
所以我"删除"属于foo对象的Bar对象,Bar.Deleted设置为true,Bar更新而不是删除。但是已经加载到上下文中的foo对象识别出bar对象已被删除"和" foo.BarId"设置为NULL
,此更改将在调用SaveChanges时传播。我们希望" foo.BarId"保持相同的价值。
有没有办法告诉Entity Framework在数据库优先模式下停止将外键置零?
答案 0 :(得分:0)
好吧,您正在将您的实体标记为已修改。
问题是,您正在标记的对象,从数据库加载的区域以及使用相同的上下文实例进行更新的区域?
如果没有,在连接它们时,是否正确设置了它们的外键(您可以从视图模型或商业模型中映射它们而不传输FK值)?
因为,如果没有,EF将为你归零FKs(0或FK中的空字符串为db db)。