前言

不知道大家是否和我有同样的问题:

一般在数据库的设计阶段,会制定一些默认的规则,其中有一条硬性规定就是一定不要对任何表中的数据执行delete硬删除操作,因为每条数据对我们来说都是有用的,并且是值得分析的。

所以我们一般会在每张表中加一个“是否删除IsDeleted”或者“是否有效IsValid”的字段,来标识这条数据的状态是否可用!

那么疑问来了,在写SQL或者Linq的时候我们到底是要加上这个条件还是忽略这个条件呢?答案当然是根据实际业务需求和情况来决定。比如一个商品,在货架上的时候,它肯定是有效的并且是供顾客进行选购的;但是有一天被通知下架了(删除了),那么在顾客的已订单列表中你也同样要显示出来供顾客查看!

不过话说回来,我觉得大多时候查询的时候我们都会将这些无效的数据给过滤掉,所以每个SQL或者Linq中都有随处可见的IsDeleted=0类似这样的条件,而且有时候我们还会一不小心就把这个条件忘记在了脑后。那么有没有一种一劳永逸的或者更加便捷的方法来解决这个问题呢?这时主角EF Core就上场了!

1、使用EF Core自带的全局过滤查询功能

这个使用非常之简单,只需要在OnModelCreating中对需要进行全局过滤的表实体中设置ModelBuilder就可以了。先在系统用户表里边准备一条删除和未删除的数据。

    /// <summary>
/// 系统上下文
/// </summary>
public class LightContext : DbContext
{
public LightContext(DbContextOptions<LightContext> options) : base(options)
{
} protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ApplicationUser>(m =>
{
m.Property(t => t.Email)
.HasMaxLength(); m.Property(t => t.UserName)
.IsRequired()
.HasMaxLength(); m.Property(t => t.Password)
.IsRequired()
.HasMaxLength(); m.HasQueryFilter(n => !n.IsDeleted); //默认查询未删除的用户
});
base.OnModelCreating(modelBuilder);
} /// <summary>
/// 系统应用用户
/// </summary>
public DbSet<ApplicationUser> ApplicationUser { get; set; }
}

运行程序然后请求用户接口,那么结果就是我们只获取到Id=1的未删除数据,Id=2的数据已经达到了我们的预期被过滤掉了!

分析:上面的做法虽然达到了效果,但是还不够灵活。如果这时我要查询所有的数据,那么这个全局过滤条件还得删掉,还有就是如果我要偏偏查询已删除的数据呢,又得改代码了!

所以,我们每次查询的时候都需要接受一个条件,来标识所查询数据的有效性,并将这个条件参数传递给数据库上下文DbContext,动态的去获取我们想要的数据!

2、在ASP.NET Core中接受全局过滤参数

首先第一步我们要在服务配置项中借助请求上下文HttpContext来动态接受一个“是否删除”的参数对象,我们暂时将这个参数定义为“d”,含义分别为:0:未删除,1:已删除,2:全部,同样默认查询所有未删除的数据

然后将这个参数以数据库上下文DbContext的构造函数传递进去,同时要考虑到get请求和post请求,最终的代码如下:

        public void ConfigureServices(IServiceCollection services)
{
// Add DbContext
//services.AddDbContext<LightContext>(options =>
// options.UseSqlServer(Configuration.GetConnectionString("LightConnection"))); services.AddTransient<LightContext>(factory =>
{
var builder = new DbContextOptionsBuilder<LightContext>();
builder.UseSqlServer(Configuration.GetConnectionString("LightConnection")); var accessor = factory.GetService<IHttpContextAccessor>();
bool? isDeleted = false;//默认全局查询未删除的数据 if (accessor.HttpContext != null)
{
string method = accessor.HttpContext.Request.Method.ToLower();
StringValues queryIsdeleted = StringValues.Empty;
if (method == "get")
{
queryIsdeleted = accessor.HttpContext.Request.Query["d"];
}
else if (method == "post" && accessor.HttpContext.Request.HasFormContentType)
{
queryIsdeleted = accessor.HttpContext.Request.Form["d"];
}
if (!StringValues.IsNullOrEmpty(queryIsdeleted))
{
int isDeletedInt = ;//0:未删除,1:已删除,2:全部
if (int.TryParse(queryIsdeleted.FirstOrDefault(), out isDeletedInt))
{
if (isDeletedInt == )
{
isDeleted = false;
}
else if (isDeletedInt == )
{
isDeleted = true;
}
else if (isDeletedInt == )
{
isDeleted = null;
}
}
}
}
return new LightContext(builder.Options, isDeleted);
});
}

3、在EF Core仓储中添加自定义过滤条件

接下来在数据库上下文DbContext增加一个IsDeleted的查询条件并私有化赋值操作,仅仅交由构造函数进行赋值。改动的代码如下:

    /// <summary>
/// 系统上下文
/// </summary>
public class LightContext : DbContext
{
public bool? IsDeleted { get; private set; } //禁止外界对IsDeleted进行赋值操作,限制在构造函数赋值 public LightContext(DbContextOptions<LightContext> options, bool? isDeleted = false) : base(options)
{
IsDeleted = isDeleted;
}
}

然后这个条件就可以在我们的EF仓储模块进行使用了,根据我们的实际需求可以进行不同的条件查询,部分代码如下:

    /// <summary>
/// EF 实现仓储接口
/// </summary>
/// <typeparam name="T">实体</typeparam>
public class EfRepository<T> : IRepository<T>, IRepositoryAsync<T> where T : BaseModel
{
protected readonly LightContext _lightContext; public EfRepository(LightContext lightContext)
{
_lightContext = lightContext;
} public T GetById(int id)
{
if (_lightContext.IsDeleted.HasValue)
{
return _lightContext.Set<T>().Where(m => m.IsDeleted == _lightContext.IsDeleted.Value).FirstOrDefault(m => m.Id == id);
}
return _lightContext.Set<T>().FirstOrDefault(m => m.Id == id);
} public async Task<T> GetByIdAsync(int id)
{
if (_lightContext.IsDeleted.HasValue)
{
return await _lightContext.Set<T>().Where(m => m.IsDeleted == _lightContext.IsDeleted.Value).FirstOrDefaultAsync(m => m.Id == id);
}
return await _lightContext.Set<T>().FirstOrDefaultAsync(m => m.Id == id);
} public IEnumerable<T> GetList()
{
if (_lightContext.IsDeleted.HasValue)
{
return _lightContext.Set<T>().Where(m => m.IsDeleted == _lightContext.IsDeleted.Value).ToList();
}
return _lightContext.Set<T>().ToList();
} public async Task<IEnumerable<T>> GetListAsync()
{
if (_lightContext.IsDeleted.HasValue)
{
return await _lightContext.Set<T>().Where(m => m.IsDeleted == _lightContext.IsDeleted.Value).ToListAsync();
}
return await _lightContext.Set<T>().ToListAsync();
}
}

最后EF Core自带的那个过滤查询就可以完全忽略掉了:

//m.HasQueryFilter(n => !n.IsDeleted); //默认查询未删除的用户

至此整个调整已经完成,虽然看似简单,但是感觉还挺实用的,同样如果需要其他通用的过滤条件,比如时间之类的,都可以酌情添加!最终的效果如下:

4、最后

每天进步一点点,是件很愉快的事情!提前预祝大家新年快乐:)

在ASP.NET Core中通过EF Core实现一个简单的全局过滤查询的更多相关文章

  1. ASP.NET Core 中使用EF Core 将实体映射到数据库表的方法(SQL Server)

    前段时间听过一个关于使用ASP.NET Core建立项目的视频.其中使用EF Core映射到数据库的部分是按部就班地学习.今天自己建立项目时,有些步骤已经有一些遗忘.所以写下这篇文章,顺便理清思路. ...

  2. ASP.NET Core中使用EF Core(MySql)Database First

    ⒈创建数据库,在数据中执行以下脚本. CREATE DATABASE Blogging; USE Blogging; CREATE TABLE Blog ( BlogId int not null P ...

  3. ASP.NET Core中使用EF Core(MySql)Code First

    ⒈添加依赖 MySql.Data.EntityFrameworkCore ⒉在appsettings.json配置文件中配置数据库连接字符串 { "Logging": { &quo ...

  4. .NET Core中使用EF Core连接MySQL

    最近一直在捣鼓.NET Core方面的东西,顺便写下点东西记录下 1.打开vs2017,新建一个项目 2.vs会自动生成一个项目,然后打开NuGet搜索MySql.Data.EntityFramewo ...

  5. Asp.net core下利用EF core实现从数据实现多租户(1)

    前言 随着互联网的的高速发展,大多数的公司由于一开始使用的传统的硬件/软件架构,导致在业务不断发展的同时,系统也逐渐地逼近传统结构的极限. 于是,系统也急需进行结构上的升级换代. 在服务端,系统的I/ ...

  6. Asp.net core下利用EF core实现从数据实现多租户(3): 按Schema分离 附加:EF Migration 操作

    前言 前段时间写了EF core实现多租户的文章,实现了根据数据库,数据表进行多租户数据隔离. 今天开始写按照Schema分离的文章. 其实还有一种,是通过在数据表内添加一个字段做多租户的,但是这种模 ...

  7. 万字长文,带你彻底理解EF Core5的运行机制,让你成为团队中的EF Core专家

    在EF Core 5中,有很多方式可以窥察工作流程中发生的事情,并与该信息进行交互.这些功能点包括日志记录,拦截,事件处理程序和一些超酷的最新出现的调试功能.EF团队甚至从Entity Framewo ...

  8. [翻译 EF Core in Action 1.10] 应该在项目中使用EF Core吗?

    Entity Framework Core in Action Entityframework Core in action是 Jon P smith 所著的关于Entityframework Cor ...

  9. EF Core 快速上手——EF Core 入门

    EF Core 快速上手--EF Core 介绍 本章导航 从本书你能学到什么 对EF6.x 程序员的一些话 EF Core 概述 1.3.1 ORM框架的缺点 第一个EF Core应用   本文是对 ...

随机推荐

  1. 搭建CAS服务器,并实现一个简单的单点登录的demo

    官网:http://jasig.github.io/cas/Cas Server下载:http://developer.jasig.org/cas/Cas Client下载:http://develo ...

  2. iOS学习——属性引用self.xx与_xx的区别

    在iOS开发过程中,我们用@proprety声明一个属性后,在代码中我们可以用self.xx与_xx来获取到这个属性.但是一直有一个疑惑,那就是这两个之间有什么区别呢?最初我一直觉得这两个之间没什么区 ...

  3. vue2.0 关于Vue实例的生命周期

    什么是生命周期 Vue实例有一个完整的生命周期,也就是从开始创建.初始化数据.编译模板.挂载Dom.渲染→更新→渲染.卸载等一系列过程,我们称这是Vue的生命周期.通俗说就是Vue实例从创建到销毁的过 ...

  4. angular4.0如何引入外部插件1:import方案

    引入外部插件是项目中非常重要的环节.因为部分插件以js语法写的,而ng4用的是ts语法,所以在引入时需要配置. Step1:引入swiper插件的js文件[css在下面会讲到,先别急] 很重要的意见: ...

  5. icon图标和文字整体居中在button按钮

    icon图标和文字整体居中在button按钮 icon图标和文字整体居中 一般我们常做的button按钮是文字居中 现在这个需要icon图标和文字一起居中在背景色 <a href="# ...

  6. 第七章:Python基础のXML操作和面向对象(一)

    本課主題 XML介绍与操作实战 shutil 模块介绍与操作实战 subprocess 模块介绍与操作实战 初探面向对象与操作实战 本周作业 XML介绍和操作实战 對於浏览器返回的字符串有以下幾種: ...

  7. ghost.py在代用JavaScript时的超时问题

    在写爬虫的时候,关于JavaScript的解析问题,我在网上找到的一个解决方案是使用ghost.py这个模块,他是一个基于webkit封装的一个客户端,可以用来解析动态页面.它的使用非常简单,它从2. ...

  8. windows平台调用函数堆栈的追踪方法

    在windows平台,有一个简单的方法来追踪调用函数的堆栈,就是利用函数CaptureStackBackTrace,但是这个函数不能得到具体调用函数的名称,只能得到地址,当然我们可以通过反汇编的方式通 ...

  9. request拿各种东西

    例如 : http://localhost:8080/projectName/aaa/bbb?name=zhangsan获取项目名(目录) /projectNameString uri = reque ...

  10. linux下的外网木马前期要的工具

    这周看了demon哥的博客弄msf外网马,自己试了一下 首先去ngrok官网下载对应的系统版本,如果对应下载那个标签是绿色的(这里不支持windows) 下载好后在linux提取出来 让我们来看看他的 ...