使用实体框架软删除(是历史列)

时间:2009-12-21 20:48:13

标签: entity-framework soft-delete

我正在使用一个数据库,设计人员决定用IsHistorical位列标记每个表。没有考虑正确的建模,我无法改变架构。

在开发与导航属性交互的CRUD屏幕时,这会引起一些摩擦。我不能简单地拿一个产品然后编辑它的EntityCollection我必须手动编写IsHistorical检查到处都是它让我疯了。

添加也很可怕,因为到目前为止,我已经编写了所有手动检查以查看添加是否只是软删除,因此我可以只切换IsHistoric而不是添加重复的实体。

我考虑过的三个选项是:

  1. 修改t4模板以包含IsHistorical检查和同步。

  2. 拦截ObjectContext中的删除和添加,切换IsHistorical列,然后同步对象状态。

  3. 订阅AssociationChanged事件并在那里切换IsHistorical列。

  4. 有没有人有这方面的经验或者可以推荐最无痛的方法?

    注意:是的,我知道,这是糟糕的建模。我已经阅读了有关软删除的相同文章。它很臭,我必须处理这个要求,但我这样做。我只想要最轻松的方法来处理软删除,而无需为我的数据库中的每个导航属性编写相同的代码。

    注意#2 LukeLed的答案在技术上是正确的,虽然迫使你陷入一个非常糟糕的穷人ORM,无图形的模式。问题在于,现在我需要从图中删除所有“已删除”的对象,然后在每个对象上调用Delete方法。那不是真的会省去那么多手工仪式编码。现在我没有编写手动IsHistoric检查,而是收集已删除的对象并循环遍历它们。

3 个答案:

答案 0 :(得分:8)

我在我的代码中使用通用存储库。你可以这样做:

public class Repository<T> : IRepository<T> where T : EntityObject
{
    public void Delete(T obj)
    {
        if (obj is ISoftDelete)
            ((ISoftDelete)obj).IsHistorical = true
        else
            _ctx.DeleteObject(obj);
    }

您的List()方法也会按IsHistorical进行过滤。

修改

ISoftDelete界面:

public interface ISoftDelete
{
    bool IsHistorical { get; set; }
}

实体类可以很容易地标记为ISoftDelete,因为它们是部分的。部分类定义需要添加到单独的文件中:

public partial class MyClass : EntityObject, ISoftDelete
{

}

答案 1 :(得分:5)

我确信你知道,当你无法修改架构时,这个问题不会有很好的解决方案。鉴于你不喜欢Repository选项(不过,我想知道你是不是有点急于解雇它),这是我能想到的最好的选择:

  1. 处理ObjectContext.SavingChanges
  2. 当该事件触发时,通过ObjectStateManager搜索已删除状态的对象。如果它们具有IsHistorical属性,请设置该属性,并将对象的状态更改为已修改。
  3. 当涉及到协会/关系时,这可能会变得棘手,但我认为它或多或少会做你想要的。

答案 2 :(得分:0)

我使用存储库模式也使用与LukLed类似的代码,但我使用反射来查看 IsHistorical 属性是否存在(因为它是一个商定的命名约定):

public class Repository<TEntityModel> where TEntityModel : EntityObject, new() 
{
       public void Delete(TEntityModel entity)
        {
            // see if the object has an "IsHistorical" flag
            if (typeof(TEntityModel).GetProperty("IsHistorical") != null);
            {
                // perform soft delete
                var historicalProperty = entity.GetType().GetProperty("IsHistorical");
                historicalProperty.SetValue(entity, true, null);
            }
            else
            {
                // perform real delete
                EntityContext.DeleteObject(entity);
            }

            EntityContext.SaveChanges();                
        }
}

然后使用简单:

using (var fubarRepository = new Repository<Fubar>)
{
   fubarRepository.Delete(someFubar); 
}

当然,在实践中,您通过传递PK而不是实例化实体来扩展它以允许删除。