本文翻译自《Entity Framework Core: Soft Delete using Query Filters》,由于水平有限,故无法保证翻译完全正确,欢迎指出错误。谢谢!

注意:我使用的是 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] = @p3
WHERE [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 filter
ORDER BY [t].[BlogId]

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

Entity Framework Core 软删除与查询过滤器的更多相关文章

  1. 【EF】Entity Framework Core 软删除与查询过滤器

    本文翻译自<Entity Framework Core: Soft Delete using Query Filters>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 注意 ...

  2. Entity Framework Core 关联删除

    关联删除通常是一个数据库术语,用于描述在删除行时允许自动触发删除关联行的特征:即当主表的数据行被删除时,自动将关联表中依赖的数据行进行删除,或者将外键更新为NULL或默认值. 数据库关联删除行为 我们 ...

  3. Entity Framework Core 2.0 全局查询过滤器

    不定时更新翻译系列,此系列更新毫无时间规律,文笔菜翻译菜求各位看官老爷们轻喷,如觉得我翻译有问题请挪步原博客地址 本博文翻译自: http://gunnarpeipman.com/2017/08/ef ...

  4. Entity Framework Core系列之DbContext(删除)

    上一篇我们介绍了Entity Framework Core系列之DbContext(修改),这一篇我们介绍下删除数据 修改实体的方法取决于context是否正在跟踪需要删除的实体. 下面的示例中con ...

  5. Entity Framework Core Like 查询揭秘

    在Entity Framework Core 2.0中增加一个很酷的功能:EF.Functions.Like(),最终解析为SQL中的Like语句,以便于在 LINQ 查询中直接调用. 不过Entit ...

  6. 使用Entity Framework Core需要注意的一个全表查询问题

    .NET Core 迁移工作如火如荼,今天在使用 Entity Frameowork Core(又名EF Core)时写了下面这样的 LINQ 查询表达式: .Where(u => u.Id = ...

  7. .Net Core 2.0生态(4):Entity Framework Core 2.0 特性介绍和使用指南

    前言 这是.Net Core 2.0生态生态介绍的最后一篇,EF一直是我喜欢的一个ORM框架,随着版本升级EF也发展到EF6.x,Entity Framework Core是一个支持跨平台的全新版本, ...

  8. ABP官方文档翻译 9.2 Entity Framework Core

    Entity Framework Core 介绍 DbContext 配置 在Startup类中 在模块PreInitialize方法中 仓储 默认仓储 自定义仓储 应用程序特定基础仓储类 自定义仓储 ...

  9. 【EF】Entity Framework Core 2.0 特性介绍和使用指南

    阅读目录 前言 获取和使用 新特性 项目升级和核心API变化 下一步计划 遗憾的地方 回到目录 前言 这是.Net Core 2.0生态生态介绍的最后一篇,EF一直是我喜欢的一个ORM框架,随着版本升 ...

随机推荐

  1. 【小练习05】HTML+CSS--淘宝商铺小页面

    要求实现如下效果图: 代码演示 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"&g ...

  2. css中那些容易被我们程序猿所忽略的选择器

    css中那些容易被我们程序猿所忽略的选择器 作为一个程序猿,我们可能会遇到这样的问题,假如:有5个li,要求给第三个li设置背景颜色怎么办?有人会说,用JS啊,循环遍历出第三个不就行了.但是,用JS解 ...

  3. mysql之 innobackupex备份+binlog日志的完全恢复(命令行执行模式)

    前言:MySQL的完全恢复,我们可以借助于完整的 备份+binlog 来将数据库恢复到故障点.备份可以是热备与逻辑备份(mysqldump),只要备份与binlog是完整的,都可以实现完全恢复. 1. ...

  4. winserver2008r2 + iis7安装django

    同样网上看了无数教程,但总是这个错一点那个错一点点的结果就一直没成功然后逞着今天空了那么一下午下定决定再折腾下把django跑起来,解决了静态文件问题为了方便以后复制粘贴,就全文字,嘿嘿 废话不说,接 ...

  5. 弹性盒模型 flex box

    弹性盒子模型 布局方案 传统的布局方案大多采用div+css+float+position+display来实现,但是随着css3中弹性盒子模型的推出,在前端布局方案中就又多出了一项彪悍的选项. 而因 ...

  6. mac 安装mysqldb组件包及mac中安装mysql-python遇到的问题

    错误1:mysql_config not found 问题描述:在执行sudo pip install mysql-python安装时报错误:EnvironmentError: mysql_confi ...

  7. Xamarin开发笔记—设备类&第三方弹窗的使用和注意事项

    一.设备类是Xamarin重要开发组成部分,下面介绍一下设备类的主要用法: //唤醒打电话 Device.OpenUri(new Uri("tel:180xxxxxxxx")); ...

  8. Codewars练习笔记·1 - 6.23

    Codewars地址:https://www.codewars.com/ 笔记资料来源:JavaScript高级程序设计. 欢迎和大家一起来讨论~   基础练习(1):   我的解答为: class ...

  9. Builder模式详解及其在Android开发中的应用

    一.引言 在Android开发中,采用Builder模式的代码随处可见,比如说Android系统对话框AlertDialog的使用或者是Android中的通知栏(Notification)的使用,又比 ...

  10. 关于MATLAB处理大数据坐标文件2017624

    经过一个下午找资料,已作出人工轨迹记录程序,这样就可以增加样本容量 接下来三个方向:特征.决策树.机械轨迹程序 虽然机械轨迹的程序相对好做,但是现有机械轨迹程序太过于死板,不能自行更改轨迹