数据是否删除?isDeleted的软删除还是从数据库里硬删除

别删除数据

作者 Abel Avram 译者 郭晓刚

译文转自:http://www.infoq.com/cn/news/2009/09/Do-Not-Delete-Data;jsessionid=D587371E857B557118C9ADEB5EB96B17

Oren Eini(又名Ayende Rahien)建议开发者尽量 避免数据库的软删除操作,读者可能因此认为硬删除是合理的选择。作为对Ayende文章的回应,Udi Dahan强烈建议 完全避免数据删除

所谓软删除主张在表中增加一个IsDeleted列以保持数据完整。如果某一行设置了IsDeleted标志列,那么这一行就被认为是已删除的。Ayende觉得这种方法“简单、容易理解、容易实现、容易沟通”,但“往往是错的”。问题在于:

删除一行或一个实体几乎总不是简单的事件。它不仅影响模型中的数据,还会影响模型的外观。所以我们才要有外键去确保不会出现“订单行”没有对应的父“订单”的情况。而这个例子只能算是最简单的情况。……

当采用软删除的时候,不管我们是否情愿,都很容易出现数据受损,比如谁都不在意的一个小调整,就可能使“客户”的“最新订单”指向一条已经软删除的订单。

如果开发者接到的要求就是从数据库中删除数据,要是不建议用软删除,那就只能硬删除了。为了保证数据一致性,开发者除了删除直接有关的数据行,还应该级联地删除相关数据。可Udi Dahan提醒读者注意,真实的世界并不是级联的:

假设市场部决定从商品目录中删除一样商品,那是不是说所有包含了该商品的旧订单都要一并消失?再级联下去,这些订单对应的所有发票是不是也该删除?这么一步步删下去,我们公司的损益报表是不是应该重做了?

没天理了。

问题似乎出在对“删除”这词的解读上。Dahan给出了这样的例子:

我说的“删除”其实是指这产品“停售”了。我们以后不再卖这种产品,清掉库存以后不再进货。以后顾客搜索商品或者翻阅目录的时候不会再看见这种商品,但管仓库的人暂时还得继续管理它们。“删除”是个贪方便的说法。

他接着举了一些站在用户角度的正确解读:

订单不是被删除的,是被“取消”的。订单取消得太晚,还会产生花费。

员工不是被删除的,是被“解雇”的(也可能是退休了)。还有相应的补偿金要处理。

职位不是被删除的,是被“填补”的(或者招聘申请被撤回)。

在上面这些例子中,我们的着眼点应该放在用户希望完成的任务上,而非发生在某个实体身上的技术动作。几乎在所有的情况下,需要考虑的实体总不止一个。

为了代替IsDeleted标志,Dahan建议用一个代表相关数据状态的字段:有效、停用、取消、弃置等等。用户可以借助这样一个状态字段回顾过去的数据,作为决策的依据。

删除数据除了破坏数据一致性,还有其它负面的后果。Dahan建议把所有数据都留在数据库里:“别删除。就是别删除。”

查看英文原文:Deleting Data Is Not a Recommended Practice

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 ABP 框架中,默认情况下是使用删除的方式进行删除操作的,也就是将要删除的记录的 DeletionTime 字段设置为当前时间,而不是直接从数据库删除数据。如果你需要删除数据,可以按照以下步骤进行操作: 1.在实体类中,将 SoftDelete 标记设为 false,这样就可以禁用删除功能。 ```csharp [Table("MyEntity")] public class MyEntity : Entity<int> { public string Name { get; set; } public bool IsDeleted { get; set; } = false; // 禁用删除 } ``` 2.在 DbContext 中,禁用删除的全局过滤器。 ```csharp public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) { ChangeTracker.DetectChanges(); foreach (var entityEntry in ChangeTracker.Entries()) { if (entityEntry.Entity is ISoftDelete && entityEntry.State == EntityState.Deleted) { entityEntry.State = EntityState.Modified; entityEntry.CurrentValues[nameof(ISoftDelete.IsDeleted)] = true; } } return base.SaveChangesAsync(cancellationToken); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ConfigureByConvention(); modelBuilder.Entity<MyEntity>().HasQueryFilter(e => !e.IsDeleted); // 禁用删除的全局过滤器 } ``` 3.在服务层中,直接调用仓储的 DeleteAsync 方法进行删除操作。 ```csharp public class MyEntityAppService : ApplicationService { private readonly IRepository<MyEntity, int> _myEntityRepository; public MyEntityAppService(IRepository<MyEntity, int> myEntityRepository) { _myEntityRepository = myEntityRepository; } public async Task DeleteAsync(int id) { await _myEntityRepository.DeleteAsync(id); await CurrentUnitOfWork.SaveChangesAsync(); } } ``` 这样就可以实现删除了。需要注意的是,删除会直接从数据库删除数据,如果操作不当可能会导致数据丢失,所以在使用时需要谨慎。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值