Entity Framework Core 软删除与查询过滤器

注意:我使用的是 Entity Framework Core 2.0 (2.0.0-preview2-final)。正式版发布后,功能可能存在变动。

继续探索Entity Framework Core 2.0,今天我将探讨如何轻松使用软删除(或逻辑删除)。我的意思是以透明的方式实现软删除,例如,您是物理上的删除行。要实现软删除,您需要添加一列以指示该行数据是否被逻辑删除。如果您想知道该行被删除,可以使用布尔列,如果您想知道删除的时间,可以使用日期列。其次是更改所有查询,使用此列过滤结果集;您还需要将删除语句替换成为更新语句。

现在我们来看看如何用 Entity Framework Core 来实现这两件事!

添加IsDeleted列

实体框架核心提供了非常灵活的映射。在上一篇关于跟踪列(英文原文)的博客中,您将找到映射列的3种方法。在介绍中,我已经说过软删除应该是透明的,所以我决定在类型中不暴露IsDeleted属性。类型定义如下:

public class Blog{    

public int BlogId { get; set; }    
public string Url { get; set; }  
 public List<Post> Posts { get; set; } }
 
 public class Post{  
   public int PostId { get; set; }  
     public string Title { get; set; }  
      public string Content { get; set; }  
        public int BlogId { get; set; }  
         public Blog Blog { get; set; } }

现在,我们需要向 Entity Framework Core 指明类型有一个附加列:

public class BloggingContext : DbContext{  

 public DbSet<Blog> Blogs { get; set; }  
   
   public DbSet<Post> Posts { get; set; }    
   
   protected override void OnModelCreating(ModelBuilder modelBuilder)    {        base.OnModelCreating(modelBuilder);modelBuilder.Entity<Post>().Property<bool>("IsDeleted");} }

更改插入、删除查询

Entity Framework Core 使用ChangeTracker存储所有的更改。您可以在EF生成SQL语句和执行这些语句之前修改ChangeTracker

public class BloggingContext : DbContext{  

   public override int SaveChanges(bool acceptAllChangesOnSuccess)    {OnBeforeSaving();      
   return base.SaveChanges(acceptAllChangesOnSuccess);}  
   
   public override Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))    {OnBeforeSaving();      
     return base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);}  
     
      private void OnBeforeSaving()    {  
          foreach (var entry in ChangeTracker.Entries<Post>()){          

         switch (entry.State){            
                case EntityState.Added:entry.CurrentValues["IsDeleted"] = false;    
                                break;      
                 case EntityState.Deleted:entry.State = EntityState.Modified;entry.CurrentValues["IsDeleted"] = true;    
                     break;}}} }

现在生成以下代码执行的SQL语句:

using (var context = new BloggingContext())
{   
 var post = new Post { Blog = blog };context.Posts.Add(post);context.SaveChanges(); }
exec sp_executesql N'SET NOCOUNT ON;INSERT INTO [Posts] ([BlogId], [Content], [IsDeleted], [Title])VALUES (@p1, @p2, @p3, @p4);SELECT [PostId]FROM [Posts]WHERE @@ROWCOUNT = 1 AND [PostId] = scope_identity();-- @p3 is 0 (false)',N'@p1 int,@p2 nvarchar(4000),@p3 bit,@p4 nvarchar(4000)',@p1=1,@p2=NULL,@p3=0,@p4=NULL
    context.Posts.Remove(post);context.SaveChanges();
exec sp_executesql N'SET NOCOUNT ON;UPDATE [Posts] SET [BlogId] = @p0, [Content] = @p1, [IsDeleted] = @p2, [Title] = @p3WHERE [PostId] = @p4;SELECT @@ROWCOUNT;',N'@p4 int,@p0 int,@p1 nvarchar(4000),@p2 bit,@p3 nvarchar(4000)',@p4=1,@p0=1,@p1=NULL,@p2=1,@p3=NULL

插入和删除请求已经被处理,您现在还必须更改所有查询语句。

更改查询语句

Entity Framework Core 2.0 引入了一个新的概念:查询过滤器。查询过滤器总是在生成的查询语句后面追加一个的where子句。这意味着,您可以在模型创建时声明一个实体的过滤器,然后将此过滤器隐式添加到使用该表的生成的每个查询语句中。

public class BloggingContext : DbContext{  
 protected override void OnModelCreating(ModelBuilder modelBuilder)    {        base.OnModelCreating(modelBuilder);modelBuilder.Entity<Post>().Property<bool>("IsDeleted");modelBuilder.Entity<Post>().HasQueryFilter(post => EF.Property<bool>(post, "IsDeleted") == false);} }

让我们看看查询过滤器的作用:

 var posts = context.Posts.ToList();
SELECT [p].[PostId], [p].[BlogId], [p].[Content], [p].[IsDeleted], [p].[Title]FROM [Posts] AS [p]WHERE [p].[IsDeleted] = 0 -- Query filter

查询过滤器也可以用于关联查询:

 var blogs = context.Blogs.Include(_ => _.Posts);
SELECT [_].[BlogId], [_].[Url]FROM [Blogs] AS [_]ORDER BY [_].[BlogId]SELECT [p].[PostId], [p].[BlogId], [p].[Content], [p].[IsDeleted], [p].[Title]FROM [Posts] AS [p]INNER JOIN (    SELECT [_0].[BlogId]    FROM [Blogs] AS [_0]
) AS [t] ON [p].[BlogId] = [t].[BlogId]WHERE [p].[IsDeleted] = 0 -- Query filterORDER BY [t].[BlogId]

通过查询过滤器实现软删除非常容易 :)

查询软删除的行

如果您要还原已删除的行,您必须能够查询到这些数据。这意味着您需要临时删除查询过滤器。EF已经添加了一种新方法IgnoreQueryFilters来表明您不希望将查询过滤器用于当前查询。

var deletedPosts = context.Posts.IgnoreQueryFilters()                 
   .Where(post => EF.Property<bool>(post, "IsDeleted") == true);

恢复已删除的帖子有点啰嗦,您需要更改跟踪器中查询并更新IsDeleted属性。

var deletedPosts = context.Posts.IgnoreQueryFilters().Where(post => EF.Property<bool>(post, "IsDeleted") == true);
foreach (var deletedPost in deletedPosts) {  
 var postEntry = context.ChangeTracker.Entries<Post>().First(entry => entry.Entity == deletedPost);postEntry.Property("IsDeleted").CurrentValue = false; } context.SaveChanges();

总结

使用Entity Framework Core 2.0实现软删除模式非常简单,并且可以是透明的。实际上,您可以无需更改LINQ代码的情况下,将软删除添加到现有模型中。

相关文章: 

  • Entity Framework Core 生成跟踪列

  • 在Apworks数据服务中使用基于Entity Framework Core的仓储(Repository)实现

  • Entity Framework Core的贴心:优雅处理带默认值的数据库字段

  • Entity Framework Core 实现MySQL 的TimeStamp/RowVersion 并发控制

原文地址:http://www.cnblogs.com/tdfblog/p/entity-framework-core-soft-delete-using-query-filters.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/324457.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mybatis 注解传入 list 集合​​​​​​​

转载自 mybatis 注解传入 list 集合 这里写一个查询的sql语句 首先看 mapper SelectProvider(type SqlModel.class, method "listDeviceIndex")Results(value {Result(column "index_id",property "userIndex"),Result(column "de…

ssl1341-Asteroids【最大匹配,最小点覆盖,图论】

正题 大意 一个n*n的矩阵里有m个点&#xff0c;你可以一下打掉一排或以列&#xff0c;求打掉所以点要的最小次数。 如&#xff1a; X.X .X. .X. 显然可以看出只需要打两枪。 解题思路 将行和列分为一个二分图&#xff0c;然后每个点的坐标讲x和y相连。然后求最小点覆盖 …

相比学习好的学生,老师最喜欢努力认真学习的学生

相比学习好的学生&#xff0c;老师还是更喜欢努力学习的学生。好多人有这样的错觉&#xff0c;谁学习好&#xff0c;老师就喜欢谁&#xff0c;谁就是老师面前的大红人&#xff0c;可能有的老师是这样的吧&#xff0c;但是&#xff0c;对于我来说&#xff0c;相比那些学习好的学…

Postgresql快速写入\/读取大量数据(.net)

环境及测试 使用.net驱动npgsql连接post数据库。配置&#xff1a;win10 x64, i5-4590, 16G DDR3, SSD 850EVO. postgresql 9.6.3&#xff0c;数据库与数据都安装在SSD上&#xff0c;默认配置&#xff0c;无扩展。 CREATE TABLE public.mesh (x integer NOT NULL,y integer N…

mybatis更新Blob类型字段要用updateByPrimaryKeyWithBLOBs

转载自 mybatis更新Blob类型字段要用updateByPrimaryKeyWithBLOBs 不会报错也不会更新desc 业务desc数据库类型为Blob 查看源码 解决方案:

ssl1341-最小路径覆盖【最大匹配,最小路径覆盖,图论】

正题 大意 给一个无向图&#xff0c;求最少需要多少条路径可以连接所有点。 解题思路 一个公式就好了 最小路径覆盖数最大匹配数 代码 #include<cstdio> #include<cstring> using namespace std; struct line{int x,y,next; }a[1000]; int link[121],n,m,ls[12…

Ajax实现动态及时刷新表格数据

大家好&#xff0c;我是雄雄&#xff0c;今天分享的技术很简单&#xff0c;即ajax结合jdbc动态实现及时刷新表单数据。前言&#xff1a;相信大家在网上冲浪的时候&#xff0c;肯定会发现这样的场景&#xff0c;在实现某个查询功能时&#xff0c;下方表格中会显示需要展示的结果…

扩展entity framework core实现默认字符串长度,decimal精度,entity自动注册和配置

文章以efcore 2.0.0-preview2.测试验证通过。其他版本不保证使用&#xff0c;但是思路不会差太远。源代码,报道越短&#xff0c;事情越严重&#xff01;文章越短&#xff0c;内容越精悍&#xff01; 目标&#xff1a;1.实现entity的自动发现和mapper设置.2.默认字符串长度&…

SQL语句构建器类

转载自 SQL语句构建器类 问题 Java程序员面对的最痛苦的事情之一就是在Java代码中嵌入SQL语句。这么来做通常是由于SQL语句需要动态来生成-否则可以将它们放到外部文件或者存储过程中。正如你已经看到的那样&#xff0c;MyBatis在它的XML映射特性中有一个强大的动态SQL生成方…

上机不会做?在讲台上做做试试!

上周四班上到了sql语句的查询&#xff0c;正好临近周末&#xff0c;于是就在周末的时候布置了几个增删改查的案例让回家做做。今天随便找了几个人上黑板上做&#xff0c;本以为都没有问题了呢&#xff0c;结果做的一塌糊涂……惨&#xff0c;太惨了&#xff01;当时我就在想&am…

POJ2446-Chessboard【最大匹配,二分图,奇偶建图】

正题 大意 一个n*m的棋盘上有k个洞&#xff0c;将1*2的木条放在上面&#xff0c;不能铺在洞上&#xff0c;不能重叠&#xff0c;求能不能铺满整个棋盘。 解题思路 用点来建立二分图&#xff0c;然后求最大匹配。 但是奇偶建图会快两倍。奇偶建图就是相邻的块可以相连接&…

ASP.NET Core API 版本控制

几天前&#xff0c;我和我的朋友们使用 ASP.NET Core 开发了一个API &#xff0c;使用的是GET方式&#xff0c;将一些数据返回到客户端 APP。我们在前端进行了分页&#xff0c;意味着我们将所有数据发送给客户端&#xff0c;然后进行一些data.length操作&#xff0c;以获得item…

mybatis环境搭建步骤(含配置文件代码)

1.创建web项目2.将所需要的jar包放在项目内&#xff0c;并且build-path3.创建资源文件夹resources4.在资源文件夹中创建xml文件mybatis-config.xml,文件代码如下&#xff1a;<?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE configurationPUB…

【2018.4.14】模拟赛之一-ssl2391 数列

正题 大意 求1到c中属于ab∗k(k∈N∗)ab∗k(k∈N∗)的等差数列中或属于cdk(k∈N∗)cdk(k∈N∗)等比数列中的数的个数。 解题思路 等差数列的个数可以直接用公式计算&#xff0c;然后等比数列枚举的话不会超时&#xff0c;然后用公式去重就好了 代码 #include<iostream>…

多久没有给家里打过电话了?

你多久没有给家里打过电话了&#xff1f;对于我这种常年在外&#xff0c;且工作地距家直线距离都有数百公里的人来说&#xff0c;回家可是一种极大的奢侈啊。貌似自从在济南上班以来&#xff0c;平均每年也就有空回去两次&#xff0c;第一次一般都是有急事需要赶紧赶回去&#…

Feign数据压缩传输

没使用之前 使用 使用之后

漫画:删去k个数字后的最小值

转载自 漫画&#xff1a;删去k个数字后的最小值 我们来举一个栗子&#xff1a; 给定整数 541270936&#xff0c;要求删去一个数&#xff0c;让剩下的整数尽可能小。 此时&#xff0c;无论删除哪一个数字&#xff0c;最后的结果都是从9位整数变成8位整数。既然同样是8位整数&…