using Microsoft.EntityFrameworkCore.Diagnostics; using System.Data.Common; using System.Text.RegularExpressions; using Microsoft.EntityFrameworkCore; namespace Masuit.Tools.Core; /// /// WITH (NOLOCK)全局拦截器,仅限SQL Server使用 /// /// 全局启用,无需手动调用WithNolock扩展 public class WithNoLockInterceptor(bool enableGlobalNolock = false) : DbCommandInterceptor { private static readonly Regex TableRegex = new Regex(@"(?\[\w+\] AS \[[a-zA-Z]\w*\](?! WITH \(NOLOCK\)))", RegexOptions.Multiline | RegexOptions.Compiled | RegexOptions.IgnoreCase); public override InterceptionResult ScalarExecuting(DbCommand command, CommandEventData eventData, InterceptionResult result) { AddWithNoLock(command); return base.ScalarExecuting(command, eventData, result); } #if NETCOREAPP3_1 public override Task> ScalarExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult result, CancellationToken cancellationToken = new CancellationToken()) { AddWithNoLock(command); return base.ScalarExecutingAsync(command, eventData, result, cancellationToken); } #else public override ValueTask> ScalarExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult result, CancellationToken cancellationToken = new CancellationToken()) { AddWithNoLock(command); return base.ScalarExecutingAsync(command, eventData, result, cancellationToken); } #endif public override InterceptionResult ReaderExecuting(DbCommand command, CommandEventData eventData, InterceptionResult result) { AddWithNoLock(command); return result; } #if NETCOREAPP3_1 public override Task> ReaderExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult result, CancellationToken cancellationToken = new CancellationToken()) { AddWithNoLock(command); return base.ReaderExecutingAsync(command, eventData, result, cancellationToken); } #else public override ValueTask> ReaderExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult result, CancellationToken cancellationToken = new CancellationToken()) { AddWithNoLock(command); return base.ReaderExecutingAsync(command, eventData, result, cancellationToken); } #endif private void AddWithNoLock(DbCommand command) { // 检查查询是否有标记 if (enableGlobalNolock || command.CommandText.StartsWith("-- NOLOCK")) { command.CommandText = TableRegex.Replace(command.CommandText, "${table} WITH (NOLOCK)"); } } } public static class WithNoLockExt { public static IQueryable WithNolock(this IQueryable queryable) { return queryable.TagWith("-- NOLOCK"); } } [Obsolete("请使用WithNoLockInterceptor替代")] public class QueryWithNoLockDbCommandInterceptor : WithNoLockInterceptor { }