使用 EntityFramework 进行软删除( IsHistorical 列)

发布于 2024-08-15 04:29:39 字数 836 浏览 13 评论 0原文

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

在开发与导航属性交互的 CRUD 屏幕时,这会造成一些摩擦。我不能简单地获取一个产品,然后编辑它的 EntityCollection,我必须在整个地方手动编写 IsHistorical 检查,这让我发疯。

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

我考虑过的三个选项是:

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

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

    拦截ObjectContext中的删除和添加,
  3. 订阅 AssociationChanged 事件并在那里切换 IsHistorical 列。

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

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

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

I'm working with a database where the designers decided to mark every table with a IsHistorical bit column. There is no consideration for proper modeling and there is no way I can change the schema.

This is causing some friction when developing CRUD screens that interact with navigation properties. I cannot simply take a Product and then edit its EntityCollection I have to manually write IsHistorical checks all over the place and its driving me mad.

Additions are also horrible because so far I've written all manual checks to see if an addition is just soft deleted so instead of adding a duplicate entity I can just toggle IsHistoric.

The three options I've considered are:

  1. Modifying the t4 templates to include IsHistorical checks and synchronization.

  2. Intercept deletions and additions in the ObjectContext, toggle the IsHistorical column, and then synch the object state.

  3. Subscribe to the AssociationChanged event and toggle the IsHistorical column there.

Does anybody have any experience with this or could recommend the most painless approach?

Note: Yes, I know, this is bad modeling. I've read the same articles about soft deletes that you have. It stinks I have to deal with this requirement but I do. I just want the most painless method of dealing with soft deletes without writing the same code for every navigation property in my database.

Note #2 LukeLed's answer is technically correct although forces you into a really bad poor mans ORM, graph-less, pattern. The problem lies in the fact that now I'm required to rip out all the "deleted" objects from the graph and then call the Delete method over each one. Thats not really going to save me that much manual ceremonial coding. Instead of writing manual IsHistoric checks now I'm gathering deleted objects and looping through them.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

野鹿林 2024-08-22 04:29:39

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

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
{

}

I am using generic repository in my code. You could do it like:

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);
    }

Your List() method would filter by IsHistorical too.

EDIT:

ISoftDelete interface:

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

Entity classes can be easily marked as ISoftDelete, because they are partial. Partial class definition needs to be added in separate file:

public partial class MyClass : EntityObject, ISoftDelete
{

}
无人接听 2024-08-22 04:29:39

我相信您知道,当您无法修改架构时,这个问题不会有一个很好的解决方案。鉴于您不喜欢“存储库”选项(不过,我想知道您是否只是有点仓促地放弃它),这是我能想到的最好的方法:

  1. Handle ObjectContext.SavingChanges
  2. 当该事件触发时,在 ObjectStateManager 中查找处于已删除状态的对象。如果它们具有 IsHistorical 属性,请设置该属性,并将对象的状态更改为已修改。

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

As I'm sure you're aware, there is not going to be a great solution to this problem when you cannot modify the schema. Given that you don't like the Repository option (though, I wonder if you're not being just a bit hasty to dismiss it), here's the best I can come up with:

  1. Handle ObjectContext.SavingChanges
  2. When that event fires, trawl through the ObjectStateManager looking for objects in the deleted state. If they have an IsHistorical property, set that, and changed the state of the object to modified.

This could get tricky when it comes to associations/relationships, but I think it more or less does what you want.

筑梦 2024-08-22 04:29:39

我也使用与 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 而不是实例化实体等来扩展它以允许删除。

I use the repository pattern also with similar code to LukLed's, but I use reflection to see if the IsHistorical property is there (since it's an agreed upon naming convention):

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();                
        }
}

Usage is then simply:

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

Of course, in practice, you extend this to allow deletes by passing PK instead of an instantiated entity, etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文