Skip to content

Commit a9205d0

Browse files
committed
Improve ShouldSkipProcessing by involving ShouldSkipCachingCommands
1 parent aeb46b4 commit a9205d0

File tree

10 files changed

+193
-157
lines changed

10 files changed

+193
-157
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<VersionPrefix>5.2.5</VersionPrefix>
3+
<VersionPrefix>5.3.0</VersionPrefix>
44
<LangVersion>latest</LangVersion>
55
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
66
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
using System.Data.Common;
2+
using Microsoft.EntityFrameworkCore;
3+
using Microsoft.Extensions.Logging;
4+
using Microsoft.Extensions.Options;
5+
6+
namespace EFCoreSecondLevelCacheInterceptor;
7+
8+
/// <summary>
9+
/// Helps process SecondLevelCacheInterceptor
10+
/// </summary>
11+
public class DbCommandIgnoreCachingProcessor(
12+
IEFCachePolicyParser cachePolicyParser,
13+
IEFSqlCommandsProcessor sqlCommandsProcessor,
14+
IOptions<EFCoreSecondLevelCacheSettings> cacheSettings,
15+
IEFDebugLogger logger,
16+
ILogger<DbCommandIgnoreCachingProcessor> interceptorProcessorLogger) : IDbCommandIgnoreCachingProcessor
17+
{
18+
/// <summary>
19+
/// Is this command marked for caching?
20+
/// </summary>
21+
public (bool ShouldSkipProcessing, EFCachePolicy? CachePolicy) ShouldSkipProcessing(DbCommand? command,
22+
DbContext? context,
23+
CancellationToken cancellationToken = default)
24+
{
25+
if (context is null || command is null)
26+
{
27+
return (true, null);
28+
}
29+
30+
if (cancellationToken.IsCancellationRequested)
31+
{
32+
return (true, null);
33+
}
34+
35+
var commandCommandText = command.CommandText ?? "";
36+
37+
if (ShouldSkipCachingDbContext(context, commandCommandText))
38+
{
39+
return (true, null);
40+
}
41+
42+
var (cachePolicy, shouldSkipCaching) = GetCachePolicy(context, commandCommandText);
43+
44+
if (shouldSkipCaching)
45+
{
46+
return (true, cachePolicy);
47+
}
48+
49+
if (ShouldSkipQueriesInsideExplicitTransaction(command))
50+
{
51+
return (!sqlCommandsProcessor.IsCrudCommand(commandCommandText), cachePolicy);
52+
}
53+
54+
if (sqlCommandsProcessor.IsCrudCommand(commandCommandText))
55+
{
56+
return (false, cachePolicy);
57+
}
58+
59+
return cachePolicy is null ? (true, null) : (false, cachePolicy);
60+
}
61+
62+
/// <summary>
63+
/// Skip caching of this result based on the provided predicate
64+
/// </summary>
65+
public bool ShouldSkipCachingResults(string commandText, object value)
66+
{
67+
var result = cacheSettings.Value.SkipCachingResults != null &&
68+
cacheSettings.Value.SkipCachingResults((commandText, value));
69+
70+
if (result && logger.IsLoggerEnabled)
71+
{
72+
var message = "Skipped caching of this result based on the provided predicate.";
73+
interceptorProcessorLogger.LogDebug(message);
74+
logger.NotifyCacheableEvent(CacheableLogEventId.CachingSkipped, message, commandText, efCacheKey: null);
75+
}
76+
77+
return result;
78+
}
79+
80+
private bool ShouldSkipCachingDbContext(DbContext context, string commandText)
81+
{
82+
var result = cacheSettings.Value.SkipCachingDbContexts is not null &&
83+
cacheSettings.Value.SkipCachingDbContexts.Contains(context.GetType());
84+
85+
if (result && logger.IsLoggerEnabled)
86+
{
87+
var message = $"Skipped caching of this DbContext: {context.GetType()}";
88+
interceptorProcessorLogger.LogDebug(message);
89+
logger.NotifyCacheableEvent(CacheableLogEventId.CachingSkipped, message, commandText, efCacheKey: null);
90+
}
91+
92+
return result;
93+
}
94+
95+
private bool ShouldSkipQueriesInsideExplicitTransaction(DbCommand? command)
96+
=> !cacheSettings.Value.AllowCachingWithExplicitTransactions && command?.Transaction is not null;
97+
98+
private (EFCachePolicy? CachePolicy, bool ShouldSkipCaching) GetCachePolicy(DbContext context, string commandText)
99+
{
100+
var allEntityTypes = sqlCommandsProcessor.GetAllTableNames(context);
101+
102+
return cachePolicyParser.GetEFCachePolicy(commandText, allEntityTypes);
103+
}
104+
}

src/EFCoreSecondLevelCacheInterceptor/DbCommandInterceptorProcessor.cs

Lines changed: 11 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
using System;
21
using System.Data.Common;
32
using System.Globalization;
4-
using System.Threading;
53
using Microsoft.EntityFrameworkCore;
64
using Microsoft.EntityFrameworkCore.Diagnostics;
75
using Microsoft.Extensions.Logging;
@@ -10,41 +8,38 @@
108
namespace EFCoreSecondLevelCacheInterceptor;
119

1210
/// <summary>
13-
/// Helps processing SecondLevelCacheInterceptor
11+
/// Helps process SecondLevelCacheInterceptor
1412
/// </summary>
1513
public class DbCommandInterceptorProcessor : IDbCommandInterceptorProcessor
1614
{
1715
private readonly IEFCacheDependenciesProcessor _cacheDependenciesProcessor;
1816
private readonly IEFCacheKeyProvider _cacheKeyProvider;
19-
private readonly IEFCachePolicyParser _cachePolicyParser;
2017
private readonly IEFCacheServiceProvider _cacheService;
2118
private readonly IEFCacheServiceCheck _cacheServiceCheck;
2219
private readonly EFCoreSecondLevelCacheSettings _cacheSettings;
20+
private readonly IDbCommandIgnoreCachingProcessor _ignoreCachingProcessor;
2321
private readonly ILogger<DbCommandInterceptorProcessor> _interceptorProcessorLogger;
2422
private readonly IEFDebugLogger _logger;
25-
private readonly IEFSqlCommandsProcessor _sqlCommandsProcessor;
2623

2724
/// <summary>
28-
/// Helps processing SecondLevelCacheInterceptor
25+
/// Helps process SecondLevelCacheInterceptor
2926
/// </summary>
3027
public DbCommandInterceptorProcessor(IEFDebugLogger logger,
3128
ILogger<DbCommandInterceptorProcessor> interceptorProcessorLogger,
3229
IEFCacheServiceProvider cacheService,
3330
IEFCacheDependenciesProcessor cacheDependenciesProcessor,
3431
IEFCacheKeyProvider cacheKeyProvider,
35-
IEFCachePolicyParser cachePolicyParser,
36-
IEFSqlCommandsProcessor sqlCommandsProcessor,
3732
IOptions<EFCoreSecondLevelCacheSettings> cacheSettings,
38-
IEFCacheServiceCheck cacheServiceCheck)
33+
IEFCacheServiceCheck cacheServiceCheck,
34+
IDbCommandIgnoreCachingProcessor ignoreCachingProcessor)
3935
{
4036
_cacheService = cacheService;
4137
_cacheDependenciesProcessor = cacheDependenciesProcessor;
4238
_cacheKeyProvider = cacheKeyProvider;
43-
_cachePolicyParser = cachePolicyParser;
4439
_logger = logger;
4540
_interceptorProcessorLogger = interceptorProcessorLogger;
46-
_sqlCommandsProcessor = sqlCommandsProcessor;
4741
_cacheServiceCheck = cacheServiceCheck;
42+
_ignoreCachingProcessor = ignoreCachingProcessor;
4843

4944
if (cacheSettings == null)
5045
{
@@ -73,7 +68,7 @@ public T ProcessExecutedCommands<T>(DbCommand command, DbContext? context, T res
7368
return result;
7469
}
7570

76-
var (shouldSkipProcessing, cachePolicy) = ShouldSkipProcessing(command, context);
71+
var (shouldSkipProcessing, cachePolicy) = _ignoreCachingProcessor.ShouldSkipProcessing(command, context);
7772

7873
if (shouldSkipProcessing)
7974
{
@@ -116,7 +111,7 @@ public T ProcessExecutedCommands<T>(DbCommand command, DbContext? context, T res
116111

117112
if (result is int data)
118113
{
119-
if (!ShouldSkipCachingResults(commandText, data))
114+
if (!_ignoreCachingProcessor.ShouldSkipCachingResults(commandText, data))
120115
{
121116
_cacheService.InsertValue(efCacheKey, new EFCachedData
122117
{
@@ -145,7 +140,7 @@ public T ProcessExecutedCommands<T>(DbCommand command, DbContext? context, T res
145140
tableRows = dbReaderLoader.Load();
146141
}
147142

148-
if (!ShouldSkipCachingResults(commandText, tableRows))
143+
if (!_ignoreCachingProcessor.ShouldSkipCachingResults(commandText, tableRows))
149144
{
150145
_cacheService.InsertValue(efCacheKey, new EFCachedData
151146
{
@@ -171,7 +166,7 @@ public T ProcessExecutedCommands<T>(DbCommand command, DbContext? context, T res
171166

172167
if (result is object)
173168
{
174-
if (!ShouldSkipCachingResults(commandText, result))
169+
if (!_ignoreCachingProcessor.ShouldSkipCachingResults(commandText, result))
175170
{
176171
_cacheService.InsertValue(efCacheKey, new EFCachedData
177172
{
@@ -231,7 +226,7 @@ public T ProcessExecutingCommands<T>(DbCommand command, DbContext? context, T re
231226
return result;
232227
}
233228

234-
var (shouldSkipProcessing, cachePolicy) = ShouldSkipProcessing(command, context);
229+
var (shouldSkipProcessing, cachePolicy) = _ignoreCachingProcessor.ShouldSkipProcessing(command, context);
235230

236231
if (shouldSkipProcessing)
237232
{
@@ -371,83 +366,4 @@ public T ProcessExecutingCommands<T>(DbCommand command, DbContext? context, T re
371366
return result;
372367
}
373368
}
374-
375-
/// <summary>
376-
/// Is this command marked for caching?
377-
/// </summary>
378-
private (bool ShouldSkipProcessing, EFCachePolicy? CachePolicy) ShouldSkipProcessing(DbCommand? command,
379-
DbContext? context,
380-
CancellationToken cancellationToken = default)
381-
{
382-
if (context is null || command is null)
383-
{
384-
return (true, null);
385-
}
386-
387-
if (cancellationToken.IsCancellationRequested)
388-
{
389-
return (true, null);
390-
}
391-
392-
var commandCommandText = command.CommandText ?? "";
393-
394-
if (ShouldSkipCachingDbContext(context, commandCommandText))
395-
{
396-
return (true, null);
397-
}
398-
399-
var cachePolicy = GetCachePolicy(context, commandCommandText);
400-
401-
if (ShouldSkipQueriesInsideExplicitTransaction(command))
402-
{
403-
return (!_sqlCommandsProcessor.IsCrudCommand(commandCommandText), cachePolicy);
404-
}
405-
406-
if (_sqlCommandsProcessor.IsCrudCommand(commandCommandText))
407-
{
408-
return (false, cachePolicy);
409-
}
410-
411-
return cachePolicy is null ? (true, null) : (false, cachePolicy);
412-
}
413-
414-
private bool ShouldSkipCachingDbContext(DbContext context, string commandText)
415-
{
416-
var result = _cacheSettings.SkipCachingDbContexts is not null &&
417-
_cacheSettings.SkipCachingDbContexts.Contains(context.GetType());
418-
419-
if (result && _logger.IsLoggerEnabled)
420-
{
421-
var message = $"Skipped caching of this DbContext: {context.GetType()}";
422-
_interceptorProcessorLogger.LogDebug(message);
423-
_logger.NotifyCacheableEvent(CacheableLogEventId.CachingSkipped, message, commandText, efCacheKey: null);
424-
}
425-
426-
return result;
427-
}
428-
429-
private bool ShouldSkipQueriesInsideExplicitTransaction(DbCommand? command)
430-
=> !_cacheSettings.AllowCachingWithExplicitTransactions && command?.Transaction is not null;
431-
432-
private EFCachePolicy? GetCachePolicy(DbContext context, string commandText)
433-
{
434-
var allEntityTypes = _sqlCommandsProcessor.GetAllTableNames(context);
435-
436-
return _cachePolicyParser.GetEFCachePolicy(commandText, allEntityTypes);
437-
}
438-
439-
private bool ShouldSkipCachingResults(string commandText, object value)
440-
{
441-
var result = _cacheSettings.SkipCachingResults != null &&
442-
_cacheSettings.SkipCachingResults((commandText, value));
443-
444-
if (result && _logger.IsLoggerEnabled)
445-
{
446-
var message = "Skipped caching of this result based on the provided predicate.";
447-
_interceptorProcessorLogger.LogDebug(message);
448-
_logger.NotifyCacheableEvent(CacheableLogEventId.CachingSkipped, message, commandText, efCacheKey: null);
449-
}
450-
451-
return result;
452-
}
453369
}

src/EFCoreSecondLevelCacheInterceptor/EFCachePolicyParser.cs

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
31
using System.Globalization;
4-
using System.Linq;
52
using Microsoft.Extensions.Logging;
63
using Microsoft.Extensions.Options;
74

@@ -107,21 +104,17 @@ public string RemoveEFCachePolicyTag(string commandText)
107104
/// <summary>
108105
/// Converts the `commandText` to an instance of `EFCachePolicy`
109106
/// </summary>
110-
public EFCachePolicy? GetEFCachePolicy(string commandText, IList<TableEntityInfo> allEntityTypes)
107+
public (EFCachePolicy? CachePolicy, bool ShouldSkipCaching) GetEFCachePolicy(string commandText,
108+
IList<TableEntityInfo> allEntityTypes)
111109
{
112110
if (commandText == null)
113111
{
114112
throw new ArgumentNullException(nameof(commandText));
115113
}
116114

117-
if (ContainsNonDeterministicFunction(commandText))
115+
if (ContainsNonDeterministicFunction(commandText) || ShouldSkipCachingCommands(commandText))
118116
{
119-
return null;
120-
}
121-
122-
if (ShouldSkipCachingCommands(commandText))
123-
{
124-
return null;
117+
return (null, true);
125118
}
126119

127120
var efCachePolicy = GetParsedPolicy(commandText) ?? GetSpecificGlobalPolicy(commandText, allEntityTypes) ??
@@ -138,7 +131,7 @@ public string RemoveEFCachePolicyTag(string commandText)
138131
efCacheKey: null);
139132
}
140133

141-
return efCachePolicy;
134+
return (efCachePolicy, false);
142135
}
143136

144137
private EFCachePolicy? TryOverrideCachePolicy(EFCachePolicy? efCachePolicy,

src/EFCoreSecondLevelCacheInterceptor/EFServiceCollectionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System;
21
using Microsoft.Extensions.DependencyInjection;
32
using Microsoft.Extensions.DependencyInjection.Extensions;
43
using Microsoft.Extensions.Options;
@@ -29,6 +28,7 @@ public static IServiceCollection AddEFSecondLevelCache(this IServiceCollection s
2928
services.TryAddSingleton<IEFSqlCommandsProcessor, EFSqlCommandsProcessor>();
3029
services.TryAddSingleton<IEFCacheDependenciesProcessor, EFCacheDependenciesProcessor>();
3130
services.TryAddSingleton<ILockProvider, LockProvider>();
31+
services.TryAddSingleton<IDbCommandIgnoreCachingProcessor, DbCommandIgnoreCachingProcessor>();
3232
services.TryAddSingleton<IDbCommandInterceptorProcessor, DbCommandInterceptorProcessor>();
3333
services.TryAddSingleton<SecondLevelCacheInterceptor>();
3434

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using System.Data.Common;
2+
using Microsoft.EntityFrameworkCore;
3+
4+
namespace EFCoreSecondLevelCacheInterceptor;
5+
6+
/// <summary>
7+
/// Helps process SecondLevelCacheInterceptor
8+
/// </summary>
9+
public interface IDbCommandIgnoreCachingProcessor
10+
{
11+
/// <summary>
12+
/// Is this command marked for caching?
13+
/// </summary>
14+
(bool ShouldSkipProcessing, EFCachePolicy? CachePolicy) ShouldSkipProcessing(DbCommand? command,
15+
DbContext? context,
16+
CancellationToken cancellationToken = default);
17+
18+
/// <summary>
19+
/// Skip caching of this result based on the provided predicate
20+
/// </summary>
21+
bool ShouldSkipCachingResults(string commandText, object value);
22+
}

src/EFCoreSecondLevelCacheInterceptor/IDbCommandInterceptorProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
namespace EFCoreSecondLevelCacheInterceptor;
55

66
/// <summary>
7-
/// Helps processing SecondLevelCacheInterceptor
7+
/// Helps process SecondLevelCacheInterceptor
88
/// </summary>
99
public interface IDbCommandInterceptorProcessor
1010
{

0 commit comments

Comments
 (0)