【发布时间】:2018-08-14 16:45:17
【问题描述】:
我继承了一个 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代码是Database First模式,因为数据库早在公司决定切换到Entity Framework之前就已经存在了,而且数据库的FK约束都是“ON DELETE NO ACTION”,所以我们不希望FK如果它遵循数据库的设计,则设置为 null。
我们知道 Entity Framework 不想孤立它们,但现有设计要求它们保持不变。我们期望并要求(出于审计原因)外键继续指向“已删除”行(同样,常规查询过滤掉已删除的行)。这样做的一个原因是,如果客户打电话给我们说“不小心”删除了某些东西,我们可以翻转旗帜,一切都会“正常工作”。我无法更改此设计。
以这个简化的场景代码为例:
//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 在数据库优先模式下停止将外键归零?
【问题讨论】:
-
这是我们多年来成功使用的稍微复杂一点的方法。应该做你需要的工作,让我知道这是否适合你作为答案:wiktorzychla.com/2013/10/soft-delete-pattern-for-entity.html
标签: c# entity-framework ef-database-first