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
{ }