在软删除时防止实体框架使外键清零

时间:2018-03-06 18:11:10

标签: c# entity-framework ef-database-first

我继承了一个带有数据库的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在数据库优先模式下停止将外键置零?

1 个答案:

答案 0 :(得分:0)

好吧,您正在将您的实体标记为已修改。

问题是,您正在标记的对象,从数据库加载的区域以及使用相同的上下文实例进行更新的区域?

如果没有,在连接它们时,是否正确设置了它们的外键(您可以从视图模型或商业模型中映射它们而不传输FK值)?

因为,如果没有,EF将为你归零FKs(0或FK中的空字符串为db db)。