获取entity framework6在其下面的SELECT语句中使用NOLOCK

我在MVC 5项目中使用Entity Framework 6。 如您所知,如果我们在其中使用WITH (NOLOCK) ,则SQL Server中的SELECT查询执行速度更快,效率更高。 我查看了Entity Framework 6生成的一些SQL SELECT语句,并意识到它们都不包含NOLOCK。

我不想在我的提取操作中使用事务来读取未提交的事务。

如何在下面生成的SELECT语句中强制使用EF 6来使用NOLOCK?

首先……你永远不应该为每个SQL语句使用NOLOCK。 它可能会损害数据的完整性。

这就像任何其他查询提示你应该只在你做一些与众不同的事情时才使用的机制。

无法告诉EF Provider呈现NoLock提示。 如果您确实需要读取未提交的数据,则可以使用以下选项。

  1. 编写自己的EntityFramework提供程序。

  2. 使用Command Interceptor在语句执行之前修改它。 http://msdn.microsoft.com/en-us/data/dn469464.aspx

  3. 将TransactionScope与IsolationLevel.ReadUncommited一起使用。

我知道你说你不想使用交易,但它是唯一一种读取未提交数据的开箱即用方式。 此外,它不会产生太多开销,因为SQL Server中的每个语句都“隐式”在事务中运行。

 using (new TransactionScope( TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted })) { using (var db = new MyDbContext()) { // query } } 

编辑:重要的是要注意NOLOCK for Updates和Deletes(选择保持不变)已被Microsoft从SQL Server 2016中弃用,并且将在’a’将来的版本中删除。

https://docs.microsoft.com/en-us/sql/database-engine/deprecated-database-engine-features-in-sql-server-2016?view=sql-server-2017

我同意codeworx所说的Read Uncommitted是危险的。 如果你能忍受脏读,那就去吧。

我找到了一种方法来完成这项工作而不改变当前查询中的任何内容。

你需要像这样创建一个DbCommandInterceptor:

 public class IsolationLevelInterceptor : DbCommandInterceptor { private IsolationLevel _isolationLevel; public IsolationLevelInterceptor(IsolationLevel level) { _isolationLevel = level; } //[ThreadStatic] //private DbCommand _command; public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext) { SetTransaction(command); } public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext) { SetTransaction(command); } public override void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext interceptionContext) { SetTransaction(command); } private void SetTransaction(DbCommand command) { if (command != null) { if (command.Transaction == null) { var t = command.Connection.BeginTransaction(_isolationLevel); command.Transaction = t; //_command = command; } } } } 

然后在cctor(dbcontext的静态构造函数)中,只需将拦截器添加到entity framework集合的DbInfrastructure中。

 DbInterception.Add(new IsolationLevelInterceptor()); 

这将用于EF发送到商店的每个命令,包装具有该隔离级别的事务。

在我的情况下运作良好,因为我们通过API写入数据,其中数据不是基于数据库的读数。 (由于脏读,数据可能会被破坏),因此工作正常。

您可以使用不为每个查询使用事务范围的变通方法。 如果运行以下代码,ef将对同一服务器进程ID使用相同的事务隔离级别。 由于服务器进程ID在同一请求中不会更改,因此每个请求只能调用一次就足够了。 这也适用于EF Core。

 this.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");