EntityFramework Core 3.x添加查询提示(NOLOCK)
前言
今天看到有园友写了一篇关于添加NOLOCK查询提示的博文《https://www.cnblogs.com/weihanli/p/12623934.html》,这里呢,我将介绍另外一种添加查询提示的方法,此方式源于我看过源码后的实现,孰好孰歹,请自行判之,接下来我们一起来看看。
查询提示(NOLOCK)
在EntityFramework中,如需要添加查询提示需要自定义实现拦截器,但在EntityFramework Core中除了支持实现自定义拦截器外,还可以通过继承自对应类进行复写,那就是QuerySqlGenerator类,存在于命名空间【Microsoft.EntityFrameworkCore.Query】,在此类通过我们所写的表达式实现所有查询组合,比如我们需要用到的对表的设置,如下:
protected override Expression VisitTable(TableExpression tableExpression)
{
_relationalCommandBuilder
.Append(_sqlGenerationHelper.DelimitIdentifier(tableExpression.Name, tableExpression.Schema))
.Append(AliasSeparator)
.Append(_sqlGenerationHelper.DelimitIdentifier(tableExpression.Alias)); return tableExpression;
}
同时我们可以看到还有另外一个类SqlServerQuerySqlGenerator继承自上述类,若我们需要重写的话继承自此类即可,比如在此类中进一步重写了三个表达式,我们随便看一个,如下:
protected override void GenerateTop(SelectExpression selectExpression)
{
if (selectExpression.Limit != null
&& selectExpression.Offset == null)
{
Sql.Append("TOP("); Visit(selectExpression.Limit); Sql.Append(") ");
}
}
上述意在表明:当我们进行在内存中通过Skip和Take进行分页时,因为Skip会翻译成Offset,而Take会翻译成Limit,若我们直接跳过Skip而写Take,此时在生成的Sql语句中添加TOP,很显然这是合情合理而且合法的。举个栗子,如下:
var context = new EFCoreDbContext();
context.Database.EnsureCreated(); var blogs = context.Blogs.Take().ToList();

那么此类是何时进行实例化的呢?通过SqlServerQuerySqlGeneratorFactory工厂类实例化,如下:
public class SqlServerQuerySqlGeneratorFactory : IQuerySqlGeneratorFactory
{
private readonly QuerySqlGeneratorDependencies _dependencies; public SqlServerQuerySqlGeneratorFactory(QuerySqlGeneratorDependencies dependencies)
{
_dependencies = dependencies;
} public virtual QuerySqlGenerator Create()
=> new SqlServerQuerySqlGenerator(_dependencies);
}
那么上述Sql查询工厂类到底具体是在什么时候被注册的呢,如下已省略其他注册类:
public static IServiceCollection AddEntityFrameworkSqlServer([NotNull] this IServiceCollection serviceCollection)
{
Check.NotNull(serviceCollection, nameof(serviceCollection)); var builder = new EntityFrameworkRelationalServicesBuilder(serviceCollection) // New Query Pipeline
.TryAdd<IQuerySqlGeneratorFactory, SqlServerQuerySqlGeneratorFactory>() builder.TryAddCoreServices(); return serviceCollection;
}
通过上述AddEntityFrameworkSqlServer名称可猜测该方法肯定是在实例化上下文时注册所有需要用到的接口具体实现,有了这个就好办了,为了不破坏原有的实现,我们自定义Sql查询生成类并继承自SqlServerQuerySqlGenerator并重写对表的设置并添加NOLOCK查询提示,如下:
public class CustomSqlServerQuerySqlGenerator : SqlServerQuerySqlGenerator
{
public CustomSqlServerQuerySqlGenerator(QuerySqlGeneratorDependencies dependencies)
: base(dependencies) { }
protected override Expression VisitTable(TableExpression tableExpression)
{
var result = base.VisitTable(tableExpression);
Sql.Append(" WITH (NOLOCK)");
return result;
}
}
接下来我们则需要实现自定义查询工厂并继承自默认提供的查询工厂类从而实例化上述自定义的查询类,如下:
public class CustomSqlServerQuerySqlGeneratorFactory : SqlServerQuerySqlGeneratorFactory
{
private readonly QuerySqlGeneratorDependencies _dependencies;
public CustomSqlServerQuerySqlGeneratorFactory(QuerySqlGeneratorDependencies dependencies)
: base(dependencies)
{
_dependencies = dependencies;
}
public override QuerySqlGenerator Create() =>
new CustomSqlServerQuerySqlGenerator(_dependencies);
}
那我们如何将默认提供的查询工厂类替换为上述自定义查询工厂类呢?稍微对DbContextOptionsBuilder类有所了解的童鞋应该知道,在该类中提供了ReplaceService方法来给我们替换EF Core中默认的实现,如下:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseLoggerFactory(loggerFactory)
.UseSqlServer(@"Server=.;Database=EFCore;Trusted_Connection=True;")
.ReplaceService<IQuerySqlGeneratorFactory, CustomSqlServerQuerySqlGeneratorFactory>();

到此就已经实现了添加NOLOCK查询提示,对于此种实现方式同样应该也适用于2.x版本,只不过稍微注意下对于自定义类构造函数参数可能略有不同,对于自定义实现,还是写成扩展方法比较好,这样也方便统一管理,看个人诺,比如写成如下:
public static class CustomDbContextOptionsBuilderExtensions
{
public static DbContextOptionsBuilder UseCustomSqlServerQuerySqlGenerator(this DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.ReplaceService<IQuerySqlGeneratorFactory, CustomSqlServerQuerySqlGeneratorFactory>();
return optionsBuilder;
}
}
总结
通过拦截器或者本节从源头生成Sql语句时添加对表的查询提示皆可,到底哪一个好呢?自行判断吧,其他就没啥可以进行总结的了,暂时到此为止吧。
EntityFramework Core 3.x添加查询提示(NOLOCK)的更多相关文章
- EntityFramework Core 学习笔记 —— 添加主键约束
原文地址:https://docs.efproject.net/en/latest/modeling/keys.html Keys (primary) Key 是每个实体例的主要唯一标识.EF Cor ...
- EntityFramework Core 2.0执行原始查询如何防止SQL注入?
前言 接下来一段时间我们来讲讲EntityFramework Core基础,精简的内容,深入浅出,希望为想学习EntityFramework Core的童鞋提供一点帮助. EntityFramewor ...
- EntityFramework Core笔记:查询数据(3)
1. 基本查询 1.1 加载全部数据 using System.Linq; using (var context = new LibingContext()) { var roles = contex ...
- EntityFramework Core Raw SQL
前言 本节我们来讲讲EF Core中的原始查询,目前在项目中对于简单的查询直接通过EF就可以解决,但是涉及到多表查询时为了一步到位就采用了原始查询的方式进行.下面我们一起来看看. EntityFram ...
- EntityFramework Core查询问题集锦(一)
前言 和大家脱离了一段时间,有时候总想着时间挤挤总是会有的,但是并非人愿,后面会借助周末的时间来打理博客,如有问题可以在周末私信我或者加我QQ皆可,欢迎和大家一起探讨,本节我们来讨论EF Core中的 ...
- Cookies 初识 Dotnetspider EF 6.x、EF Core实现dynamic动态查询和EF Core注入多个上下文实例池你知道有什么问题? EntityFramework Core 运行dotnet ef命令迁移背后本质是什么?(EF Core迁移原理)
Cookies 1.创建HttpCookies Cookie=new HttpCookies("CookieName");2.添加内容Cookie.Values.Add(&qu ...
- 创建ASP.NET Core MVC应用程序(5)-添加查询功能 & 新字段
创建ASP.NET Core MVC应用程序(5)-添加查询功能 & 新字段 添加查询功能 本文将实现通过Name查询用户信息. 首先更新GetAll方法以启用查询: public async ...
- 为什么NOLOCK查询提示是个不明智的想法
一些人总当NOLOCK查询提示是SQL Server里的加速器,因为它避免了大量的死锁情景.在这篇文章里,我想向你展示下为什么NOLOCK查询提示是个不好的想法. 脏读(Dirty Reads) NO ...
- EntityFramework Core 2.0 Explicitly Compiled Query(显式编译查询)
前言 EntityFramework Core 2.0引入了显式编译查询,在查询数据时预先编译好LINQ查询便于在请求数据时能够立即响应.显式编译查询提供了高可用场景,通过使用显式编译的查询可以提高查 ...
随机推荐
- django之学习前的准备
一.配置环境 Windows 10操作系统 Python安装配置教程参考:https://www.cnblogs.com/huangbiquan/p/7784533.html 安装Python虚拟环境 ...
- swagger使用以及一些注解说明
@Api:作用于Conntroller类上 value:字段说明 description:描述 tags:分组 (经常用到tags,例如如下,我只是给value,则默认应用了类名) @ApiOpera ...
- JZOJ 3927. 【NOIP2014模拟11.6】可见点数
3927. [NOIP2014模拟11.6]可见点数 (Standard IO) Time Limits: 1000 ms Memory Limits: 65536 KB Description ZP ...
- DUBBO 面试灵魂18问
一.Dubbo 是什么 dubbo 是一个分布式框架,是一个远程服务调用的分布式框架,其核心部分包含: 1)集群容错: 提供基于接口方法的透明远程过程调用,包含多协议支持,以及软负债均衡.失败容错.地 ...
- [每日一题系列] LeetCode 1013. 将数组分成和相等的三个部分
题目: 给你一个整数数组 A,只有可以将其划分为三个和相等的非空部分时才返回 true,否则返回 false. 形式上,如果可以找出索引 i+1 < j 且满足 (A[0] + A[1] + . ...
- 有了这套微信小程序x5调试,调试一些简单的开发者工具调试不了的功能不成问题!!!!
1.首先我们需要打开微信 TBS 调试 地址是:http://debugx5.qq.com 2.然后打开手机 打开开发者模式,打开 USB 调试 3.然后 在谷歌浏览器地址栏输入 chrome://i ...
- js 实现图片的放大和缩小
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 安卓手机tcpdump的使用
一.常规操作步骤 1. 手机要有root权限 2. 下载tcpdump http://www.strazzere.com/android/tcpdump 3. adb push c:\wherever ...
- (转)浅析epoll – epoll例子以及分析
原文地址:http://www.cppfans.org/1419.html 浅析epoll – epoll例子以及分析 上篇我们讲到epoll的函数和性能.这一篇用用这些个函数,给出一个最简单的epo ...
- str的常用方法
注:s表示定义的一个字符串变量,如:s = 'hello string' 1. s.index() 查找元素,若查到则返回该元素索引,含多个该元素则返回第一个,查不到则报错 s = 'hello ...