WithNoLockInterceptor.cs 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. using Microsoft.EntityFrameworkCore.Diagnostics;
  2. using System.Data.Common;
  3. using System.Text.RegularExpressions;
  4. using Microsoft.EntityFrameworkCore;
  5. namespace Masuit.Tools.Core;
  6. /// <summary>
  7. /// WITH (NOLOCK)全局拦截器,仅限SQL Server使用
  8. /// </summary>
  9. /// <param name="enableGlobalNolock">全局启用,无需手动调用WithNolock扩展</param>
  10. public class WithNoLockInterceptor(bool enableGlobalNolock = false) : DbCommandInterceptor
  11. {
  12. private static readonly Regex TableRegex = new Regex(@"(FROM|JOIN) \[[a-zA-Z]\w*\] AS \[[a-zA-Z]\w*\](?! WITH \(NOLOCK\))", RegexOptions.Multiline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
  13. public override InterceptionResult<object> ScalarExecuting(DbCommand command, CommandEventData eventData, InterceptionResult<object> result)
  14. {
  15. AddWithNoLock(command);
  16. return base.ScalarExecuting(command, eventData, result);
  17. }
  18. #if NETCOREAPP3_1
  19. public override Task<InterceptionResult<object>> ScalarExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<object> result,
  20. CancellationToken cancellationToken = new CancellationToken())
  21. {
  22. AddWithNoLock(command);
  23. return base.ScalarExecutingAsync(command, eventData, result, cancellationToken);
  24. }
  25. #else
  26. public override ValueTask<InterceptionResult<object>> ScalarExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<object> result,
  27. CancellationToken cancellationToken = new CancellationToken())
  28. {
  29. AddWithNoLock(command);
  30. return base.ScalarExecutingAsync(command, eventData, result, cancellationToken);
  31. }
  32. #endif
  33. public override InterceptionResult<DbDataReader> ReaderExecuting(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result)
  34. {
  35. AddWithNoLock(command);
  36. return result;
  37. }
  38. #if NETCOREAPP3_1
  39. public override Task<InterceptionResult<DbDataReader>> ReaderExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result,
  40. CancellationToken cancellationToken = new CancellationToken())
  41. {
  42. AddWithNoLock(command);
  43. return base.ReaderExecutingAsync(command, eventData, result, cancellationToken);
  44. }
  45. #else
  46. public override ValueTask<InterceptionResult<DbDataReader>> ReaderExecutingAsync(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result,
  47. CancellationToken cancellationToken = new CancellationToken())
  48. {
  49. AddWithNoLock(command);
  50. return base.ReaderExecutingAsync(command, eventData, result, cancellationToken);
  51. }
  52. #endif
  53. private void AddWithNoLock(DbCommand command)
  54. {
  55. // 检查查询是否有标记
  56. if (enableGlobalNolock || command.CommandText.StartsWith("-- NOLOCK"))
  57. {
  58. command.CommandText = TableRegex.Replace(command.CommandText, "$0 WITH (NOLOCK)");
  59. }
  60. }
  61. }
  62. public static class WithNoLockExt
  63. {
  64. public static IQueryable<T> WithNolock<T>(this IQueryable<T> queryable)
  65. {
  66. return queryable.TagWith("-- NOLOCK");
  67. }
  68. }
  69. [Obsolete("请使用WithNoLockInterceptor替代")]
  70. public class QueryWithNoLockDbCommandInterceptor : WithNoLockInterceptor
  71. { }