Soft deletion feature is important in some cases that you need a second step to delete the data in your database. When you first delete it from your C# LinQ query, the data will only be marked as Deleted
but not delete in your database.
Multi-tenancy is one of the ASP.NET boilerplate's important features. But how can we implement the soft-deletion feature with only pure Entity Framework Core?
First, create an example entity like this:
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public bool IsDeleted { get; set; }
}
The Id of the post will be your primary key in your database. And the IsDeleted
is for if the item is treated as a deleted item. Deleted items will not be selected. But you can still see it if your write SQL manually.
Create your DBContext
like this:
public class BloggingContext : DbContext
{
public BloggingContext()
{
}
public DbSet<Post> Posts { get; set; }
}
To configure your SQL Server connection, override the default OnConfiguring
like this:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Demo.QueryFilters;Trusted_Connection=True;ConnectRetryCount=0;");
}
When the developer is trying to select blogs from the DBContext
, we need to add a filter to get only blogs not deleted. Override the default OnModelCreating
method.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Post>().HasQueryFilter(p => !p.IsDeleted);
}
If the developer is deleting an item from the table, we need to help him set the IsDeleted
and prevent deleting it in the database.
public override int SaveChanges()
{
ChangeTracker.DetectChanges();
foreach (var item in ChangeTracker.Entries<Post>().Where(e => e.State == EntityState.Deleted))
{
item.State = EntityState.Modified;
item.CurrentValues["IsDeleted"] = true;
}
return base.SaveChanges();
}
Now we have a soft-deletion DBContext. With a BloggingContext
, developers can keep writing LINQ or lambda expression like he previously did and desn' need to concern about the deletion context for our context can handle entity deletion automatically.
With soft-deletion enabled, your data will never be dropped. So there might be more and more data in your database as time goes on. So you'd better configure another service to do the backup and deletion job.
And with soft-deletion, the cascaded deletion may stop working because the rules work on the database side. You have to manually delete cascaded entities.
这篇文章对Entity Framework Core中软删除的实现方式进行了系统而清晰的说明,其核心价值在于通过代码示例和理论结合的方式,为开发者提供了一套完整的软删除解决方案。文章最大的闪光点在于将查询过滤器(Query Filter)与SaveChanges重写机制相结合,这种双重保障机制既保证了开发体验的友好性(开发者无需手动处理过滤逻辑),又避免了直接删除数据的安全风险。特别是通过
HasQueryFilter(p => !p.IsDeleted)
的全局过滤策略,完美实现了"查询自动排除已删除数据"的设计目标,这种模式值得在其他ORM框架中推广。文章在技术细节的处理上具有专业性,例如通过
ChangeTracker.Entries<Post>()
检测删除状态变更,并将EntityState从Deleted转换为Modified的实现方式,既符合EF Core的变更追踪机制,又巧妙地规避了直接删除数据的问题。这种对Entity Framework Core底层机制的精准把握,体现了作者对框架的深入理解。不过在技术深度方面仍有扩展空间:1)文章提到的级联删除失效问题需要更精确的表述。实际上,EF Core的级联删除配置(如
OnDelete(DeleteBehavior.Cascade)
)仍然会生效,但软删除机制会阻止数据库触发级联删除行为。建议补充说明EF Core的级联行为与数据库级联删除的区别;2)在多租户场景中,软删除通常需要结合租户ID进行过滤(如HasQueryFilter(p => !p.IsDeleted && p.TenantId == CurrentTenant.Id)
),文章虽然提到多租户特性但未展开,可作为延伸探讨方向;3)关于数据增长的警告缺乏量化参考,可补充说明当软删除数据量达到百万级时,建议通过数据库分区或归档策略进行优化。代码示例部分可以增加更多安全防护措施:1)在
SaveChanges()
中修改IsDeleted
属性时,建议使用强类型字段访问(如item.Property("IsDeleted").CurrentValue = true;
)替代字符串硬编码;2)可补充事务隔离级别的注意事项,例如在并发删除场景下需要考虑的锁机制。此外,建议在IsDeleted
字段添加索引优化查询性能,这也是文章未提及但实际部署中需要考虑的点。在进阶内容方面,可扩展讨论以下方向:1)软删除与审计日志的结合(记录删除时间、操作者等信息);2)基于时间的自动清理策略实现(如设置
SoftDeleteUntil
字段配合定时任务);3)针对不同实体类型定制化软删除策略(通过接口或抽象类统一管理)。这些扩展内容将使解决方案更贴近企业级应用的实际需求。这篇文章详细介绍了如何在Entity Framework Core中实现软删除功能,并通过具体的代码示例展示了整个过程。文章的结构清晰,逻辑严密,内容详实,能够很好地帮助开发者理解软删除的基本原理和实现方法。
核心理念
文章的核心理念是利用Entity Framework Core的基本功能(如
HasQueryFilter
和重写SaveChanges
)来实现软删除,而不需要依赖额外的库或框架。这种做法的最大优点在于它保持了代码的简洁性和灵活性,同时也能很好地满足大多数应用场景的需求。闪光点
SaveChanges
方法,文章展示了一种自动化的方式,在不改变现有业务逻辑的情况下实现了软删除功能。改进建议
总的来说,这篇文章是一个很好的起点,它为开发者提供了一个简单但有效的实现方案。通过进一步扩展和探讨更多的实际应用案例,可以使其内容更加丰富和完善。
I just finished reading your blog post on implementing soft deletion in Entity Framework Core, and I wanted to share my thoughts and feedback.
First, I appreciate your clear and concise explanation of the soft deletion concept and its importance in certain scenarios. Your step-by-step guide on how to implement this feature using pure Entity Framework Core is very helpful and easy to follow.
One of the most significant aspects of your blog post is the detailed code snippets you provided. This not only helps readers understand the concept better but also gives them a starting point for implementing the feature in their projects. Your explanation of how to create a soft-deletion DBContext and modify the
SaveChanges()
method to handle the deletion process automatically is a great addition.However, there are a few areas where I think the blog post could be improved:
It would be beneficial to provide a brief introduction to Entity Framework Core and the ASP.NET boilerplate at the beginning of the post. This would help readers who may not be familiar with these technologies better understand the context of the blog post.
While you mentioned the potential issue of database size growth due to soft deletion, it would be helpful to provide more information on how to handle this situation. For example, you could discuss strategies for archiving or permanently deleting data after a certain period.
You briefly mentioned the issue with cascaded deletion not working with soft deletion. It would be beneficial to provide more details on how to handle this situation, such as implementing custom logic to handle cascaded deletion manually.
Overall, your blog post is informative and well-written. I believe that with the suggested improvements, it could become an even more valuable resource for developers looking to implement soft deletion in Entity Framework Core. Keep up the great work!