Entity framework 使用EntityFramework软删除(IShistorial列)

Entity framework 使用EntityFramework软删除(IShistorial列),entity-framework,soft-delete,Entity Framework,Soft Delete,我正在使用一个数据库,在这个数据库中,设计者决定用一个IShistorial位列标记每个表。没有考虑正确的建模,也没有办法更改模式 在开发与导航属性交互的CRUD屏幕时,这会造成一些摩擦。我不能简单地拿一个产品,然后编辑它的实体集合,我必须手工写一个到处都是的历史记录,这让我发疯 添加也很可怕,因为到目前为止,我已经编写了所有手动检查,以查看添加是否只是软删除的,所以我可以切换IsHistoric,而不是添加重复的实体 我考虑过的三种选择是: 修改t4模板以包括IShistorial检查和同步

我正在使用一个数据库,在这个数据库中,设计者决定用一个IShistorial位列标记每个表。没有考虑正确的建模,也没有办法更改模式

在开发与导航属性交互的CRUD屏幕时,这会造成一些摩擦。我不能简单地拿一个产品,然后编辑它的实体集合,我必须手工写一个到处都是的历史记录,这让我发疯

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

我考虑过的三种选择是:

  • 修改t4模板以包括IShistorial检查和同步

  • 截取ObjectContext中的删除和添加,切换Ishistorial列,然后同步对象状态

  • 订阅AssociationChanged事件并在那里切换Ishistorial列

  • 有没有人有这方面的经验,或者可以推荐最无痛的方法

    注意:是的,我知道,这是个糟糕的造型。我读过与您相同的关于软删除的文章。很糟糕,我必须满足这个要求,但我做到了。我只想要最轻松的方法来处理软删除,而不必为数据库中的每个导航属性编写相同的代码


    注意#2尽管LukeLed的回答迫使你进入一个非常糟糕的可怜人ORM、无图表的模式,但在技术上是正确的。问题在于,现在我需要从图中删除所有“已删除”的对象,然后对每个对象调用Delete方法。这并不能真正为我节省那么多的手工仪式编码。现在,我不再手工编写IsHistoric检查,而是收集已删除的对象并在其中循环。

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

    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);
        }
    
    实体类可以很容易地标记为ISoftDelete,因为它们是部分的。需要在单独的文件中添加分部类定义:

    public partial class MyClass : EntityObject, ISoftDelete
    {
    
    }
    

    我相信您已经意识到,当您无法修改模式时,将不会有很好的解决方案。考虑到您不喜欢Repository选项(不过,我想知道您是否有点草率地放弃它),下面是我能想到的最好办法:

  • 句柄
    ObjectContext.SavingChanges
  • 当该事件触发时,通过
    ObjectStateManager
    搜索处于已删除状态的对象。如果它们具有
    Ishistorial
    属性,则设置该属性,并将对象的状态更改为“修改”

  • 当涉及到关联/关系时,这可能会变得棘手,但我认为它或多或少符合您的要求。

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

    公共类存储库,其中TEntityModel:EntityObject,new()
    {
    公共作废删除(TEntityModel实体)
    {
    //查看对象是否具有“Ishistorial”标志
    if(typeof(TEntityModel).GetProperty(“Ishistorial”)!=null);
    {
    //执行软删除
    var historicalProperty=entity.GetType().GetProperty(“Ishistorial”);
    SetValue(实体,true,null);
    }
    其他的
    {
    //执行真正的删除
    EntityContext.DeleteObject(实体);
    }
    EntityContext.SaveChanges();
    }
    }
    
    用法简单地说是:

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

    当然,在实践中,您可以通过传递PK而不是实例化实体来扩展此线程以允许删除。我感觉到了您的痛苦,并将仔细监视此线程。希望你能得到答案!你为什么说它真的很差?您能解释一下吗?如果
    T
    是一个
    EntityObject
    ,那么它如何从接口
    ISoftDelete
    继承?那不是多重继承吗(在.Net中是不允许的)?@Yaakow-Ellis:那是允许的。可以从一个类继承,但可以实现任意多个接口
    ISoftDelete
    是接口。换句话说,
    ISoftDelete
    定义了一个属性:
    IsDeleted
    。没有一行代码表明
    classx
    T
    )继承自
    ISoftDelete
    。但是,如果
    X
    有一个
    IsDeleted
    属性,那么根据定义,任何实例化
    var i=new X()
    都将返回
    (i是ISoftDelete)
    为真?所以
    X
    实现接口(通过遵循其约定),即使它不是从接口继承的?这是否使用反射?这样做会极大地影响性能吗?@YaakovEllis:您必须指定,您的实体通过添加部分类定义来实现isoftdelite。接口不是通过反射来解析的。所以像这样:?这怎么不是多重继承呢?
    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); 
    }