├── .editorconfig
├── .gitattributes
├── .github
├── FUNDING.yml
├── PULL_REQUEST_TEMPLATE.md
├── dependabot.yml
├── issue_template.md
├── lock.yml
└── workflows
│ ├── build.yml
│ ├── codeql.yml
│ └── codeql
│ └── codeql-config.yml
├── .gitignore
├── Directory.Build.props
├── Directory.Packages.props
├── EFCoreSecondLevelCacheInterceptor.sln
├── LICENSE.md
├── README.md
├── global.json
├── src
├── EFCoreSecondLevelCacheInterceptor.CacheManager.Core
│ ├── EFCacheManagerCoreProvider.cs
│ ├── EFCacheManagerCoreProviderOptions.cs
│ ├── EFCoreSecondLevelCacheInterceptor.CacheManager.Core.csproj
│ └── _build.cmd
├── EFCoreSecondLevelCacheInterceptor.EasyCaching.Core
│ ├── EFCoreSecondLevelCacheInterceptor.EasyCaching.Core.csproj
│ ├── EFEasyCachingCoreProvider.cs
│ ├── EFEasyCachingCoreProviderOptions.cs
│ └── _build.cmd
├── EFCoreSecondLevelCacheInterceptor.FusionCache
│ ├── EFCoreSecondLevelCacheInterceptor.FusionCache.csproj
│ ├── EFFusionCacheConfigurationOptions.cs
│ ├── EFFusionCacheProvider.cs
│ ├── EFFusionCacheProviderOptions.cs
│ └── _build.cmd
├── EFCoreSecondLevelCacheInterceptor.HybridCache
│ ├── EFCoreSecondLevelCacheInterceptor.HybridCache.csproj
│ ├── EFHybridCacheDependenciesStore.cs
│ ├── EFHybridCacheProvider.cs
│ ├── EFHybridCacheProviderOptions.cs
│ ├── IEFHybridCacheDependenciesStore.cs
│ └── _build.cmd
├── EFCoreSecondLevelCacheInterceptor.MemoryCache
│ ├── EFCoreSecondLevelCacheInterceptor.MemoryCache.csproj
│ ├── EFMemoryCacheChangeTokenProvider.cs
│ ├── EFMemoryCacheProviderOptions.cs
│ ├── EFMemoryCacheServiceProvider.cs
│ ├── IMemoryCacheChangeTokenProvider.cs
│ └── _build.cmd
├── EFCoreSecondLevelCacheInterceptor.StackExchange.Redis
│ ├── EFCoreSecondLevelCacheInterceptor.StackExchange.Redis.csproj
│ ├── EFMessagePackDBNullFormatter.cs
│ ├── EFMessagePackSerializer.cs
│ ├── EFRedisCacheConfigurationOptions.cs
│ ├── EFStackExchangeRedisCacheProvider.cs
│ ├── EFStackExchangeRedisCacheProviderOptions.cs
│ ├── IEFDataSerializer.cs
│ └── _build.cmd
├── EFCoreSecondLevelCacheInterceptor
│ ├── AssemblyInfo.cs
│ ├── CachableQueriesOptions.cs
│ ├── CacheAllQueriesOptions.cs
│ ├── CacheExpirationMode.cs
│ ├── CacheSpecificQueriesOptions.cs
│ ├── CacheableEventId.cs
│ ├── CacheableLogEventId.cs
│ ├── DbCommandIgnoreCachingProcessor.cs
│ ├── DbCommandInterceptorProcessor.cs
│ ├── EFCacheDependenciesProcessor.cs
│ ├── EFCacheInvalidationInfo.cs
│ ├── EFCacheKey.cs
│ ├── EFCacheKeyPrefixProvider.cs
│ ├── EFCacheKeyProvider.cs
│ ├── EFCachePolicy.cs
│ ├── EFCachePolicyContext.cs
│ ├── EFCachePolicyParser.cs
│ ├── EFCacheServiceCheck.cs
│ ├── EFCacheableLogEvent.cs
│ ├── EFCachedData.cs
│ ├── EFCachedQueryExtensions.cs
│ ├── EFCoreSecondLevelCacheInterceptor.csproj
│ ├── EFCoreSecondLevelCacheOptions.cs
│ ├── EFCoreSecondLevelCacheSettings.cs
│ ├── EFDataReaderLoader.cs
│ ├── EFDebugLogger.cs
│ ├── EFServiceCollectionExtensions.cs
│ ├── EFSqlCommandsProcessor.cs
│ ├── EFTableColumnInfo.cs
│ ├── EFTableRow.cs
│ ├── EFTableRows.cs
│ ├── EFTableRowsDataReader.cs
│ ├── IDbCommandIgnoreCachingProcessor.cs
│ ├── IDbCommandInterceptorProcessor.cs
│ ├── IEFCacheDependenciesProcessor.cs
│ ├── IEFCacheKeyPrefixProvider.cs
│ ├── IEFCacheKeyProvider.cs
│ ├── IEFCachePolicyParser.cs
│ ├── IEFCacheServiceCheck.cs
│ ├── IEFCacheServiceProvider.cs
│ ├── IEFDebugLogger.cs
│ ├── IEFHashProvider.cs
│ ├── IEFSqlCommandsProcessor.cs
│ ├── ILockProvider.cs
│ ├── LockProvider.cs
│ ├── SecondLevelCacheInterceptor.cs
│ ├── SkipCacheSpecificQueriesOptions.cs
│ ├── StringExtensions.cs
│ ├── TableEntityInfo.cs
│ ├── TableNameComparison.cs
│ ├── TableTypeComparison.cs
│ ├── TypeExtensions.cs
│ ├── XxHash64Unsafe.cs
│ ├── _0-restore.bat
│ ├── _1-dotnet_pack.bat
│ └── _2-dotnet_build.bat
└── Tests
│ ├── EFCoreSecondLevelCacheInterceptor.AspNetCoreSample
│ ├── App_Data
│ │ └── .gitkeep
│ ├── Controllers
│ │ └── HomeController.cs
│ ├── EFCoreSecondLevelCacheInterceptor.AspNetCoreSample.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Startup.cs
│ ├── _0-restore.bat
│ ├── _1-dotnet_run.bat
│ └── appsettings.json
│ ├── EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar
│ ├── App_Data
│ │ └── .gitkeep
│ ├── Controllers
│ │ └── HomeController.cs
│ ├── EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Startup.cs
│ ├── _0-restore.bat
│ ├── _1-dotnet_run.bat
│ └── appsettings.json
│ ├── EFCoreSecondLevelCacheInterceptor.ConsoleSample
│ ├── EFCoreSecondLevelCacheInterceptor.ConsoleSample.csproj
│ ├── EFServiceProvider.cs
│ ├── Program.cs
│ ├── _0-restore.bat
│ ├── _1-dotnet_run.bat
│ └── appsettings.json
│ ├── EFCoreSecondLevelCacheInterceptor.PerformanceTests
│ ├── BenchmarkTests.cs
│ ├── EFCoreSecondLevelCacheInterceptor.PerformanceTests.csproj
│ ├── EFServiceProvider.cs
│ ├── Program.cs
│ ├── _0-restore.bat
│ ├── _1-dotnet_run.bat
│ ├── appsettings.json
│ └── int-pref.png
│ ├── EFCoreSecondLevelCacheInterceptor.Tests.DataLayer
│ ├── ApplicationDbContext.cs
│ ├── EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.csproj
│ ├── Entities
│ │ ├── Blog.cs
│ │ ├── DateType.cs
│ │ ├── EngineVersion.cs
│ │ ├── KeylessEntities.cs
│ │ ├── Post.cs
│ │ ├── Product.cs
│ │ ├── Tag.cs
│ │ ├── TagProduct.cs
│ │ └── User.cs
│ ├── Migrations
│ │ ├── 20201015070026_V2020_10_15_1029.Designer.cs
│ │ ├── 20201015070026_V2020_10_15_1029.cs
│ │ ├── 20250106171343_V2025_01_06_2043.Designer.cs
│ │ ├── 20250106171343_V2025_01_06_2043.cs
│ │ └── ApplicationDbContextModelSnapshot.cs
│ ├── MsSqlContextFactory.cs
│ ├── MsSqlServiceCollectionExtensions.cs
│ ├── Utils
│ │ ├── ApplicationDbContextSeedData.cs
│ │ └── DBInitialization.cs
│ ├── _0-restore.bat
│ ├── _01-add_migrations.cmd
│ └── _02-update_db.cmd
│ ├── EFCoreSecondLevelCacheInterceptor.Tests
│ ├── CacheAllQueriesTests.cs
│ ├── EFCacheDependenciesProcessorTests.cs
│ ├── EFCachePolicyParserTests.cs
│ ├── EFCacheServiceProviderTests.cs
│ ├── EFCoreSecondLevelCacheInterceptor.Tests.csproj
│ ├── ParallelTests.cs
│ ├── PerformanceTests.cs
│ ├── SecondLevelCacheInterceptorAsyncTests.cs
│ ├── SecondLevelCacheInterceptorBasicTests.cs
│ ├── SecondLevelCacheInterceptorInvalidationTests.cs
│ ├── SecondLevelCacheInterceptorSpTests.cs
│ ├── SecondLevelCacheInterceptorTransactionTests.cs
│ ├── Settings
│ │ ├── Bootstrapper.cs
│ │ ├── DBNullFormatter.cs
│ │ ├── DebugLoggerProvider.cs
│ │ ├── EFServiceProvider.cs
│ │ └── RandomNumberProvider.cs
│ ├── XxHashTests.cs
│ ├── _0-restore.bat
│ ├── _1-dotnet_test.bat
│ ├── _Issue165.bat
│ ├── _PerformanceTest.bat
│ └── appsettings.json
│ ├── EFCoreSecondLevelCacheInterceptor.UnitTests
│ ├── DbCommandInterceptorProcessorTests.cs
│ ├── EFCacheDependenciesProcessorTests.cs
│ ├── EFCacheKeyPrefixProviderTests.cs
│ ├── EFCacheKeyProviderTests.cs
│ ├── EFCacheKeyTests.cs
│ ├── EFCachePolicyParserTests.cs
│ ├── EFCacheServiceCheckTests.cs
│ ├── EFCacheServiceProviderTests.cs
│ ├── EFCoreSecondLevelCacheInterceptor.UnitTests.csproj
│ ├── EFDataReaderLoaderTests.cs
│ ├── EFDebugLoggerTests.cs
│ ├── EFServiceCollectionExtensionsTests.cs
│ ├── EFTableColumnInfoTests.cs
│ ├── EFTableRowTests.cs
│ ├── EFTableRowsDataReaderTests.cs
│ ├── EFTableRowsTests.cs
│ ├── LockProviderTests.cs
│ ├── MockDisposable.cs
│ ├── SecondLevelCacheInterceptorTests.cs
│ ├── StringExtensionsTests.cs
│ ├── TableEntityInfoTests.cs
│ ├── TypeExtensionsTests.cs
│ ├── XxHash64UnsafeTests.cs
│ └── _run_tests.cmd
│ ├── EFCoreSecondLevelCacheInterceptor.WorkerServiceWithLamar
│ ├── App_Data
│ │ └── .gitkeep
│ ├── EFCoreSecondLevelCacheInterceptor.WorkerServiceWithLamar.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Worker.cs
│ ├── _0-restore.bat
│ ├── _1-dotnet_run.bat
│ └── appsettings.json
│ ├── Issues
│ ├── Issue123WithMessagePack
│ │ ├── App_Data
│ │ │ └── .gitkeep
│ │ ├── DataLayer
│ │ │ ├── ApplicationDbContext.cs
│ │ │ └── MsSqlContextFactory.cs
│ │ ├── EFServiceProvider.cs
│ │ ├── Entities
│ │ │ └── Person.cs
│ │ ├── Issue123WithMessagePack.csproj
│ │ ├── Migrations
│ │ │ ├── 20210509052521_V2021_05_09_0954.Designer.cs
│ │ │ ├── 20210509052521_V2021_05_09_0954.cs
│ │ │ ├── 20220803082805_V2022_08_03_1257.Designer.cs
│ │ │ ├── 20220803082805_V2022_08_03_1257.cs
│ │ │ ├── 20230222181834_V2023_02_22_2147.Designer.cs
│ │ │ ├── 20230222181834_V2023_02_22_2147.cs
│ │ │ ├── 20230225090316_V2023_02_25_1232.Designer.cs
│ │ │ ├── 20230225090316_V2023_02_25_1232.cs
│ │ │ └── ApplicationDbContextModelSnapshot.cs
│ │ ├── Program.cs
│ │ ├── _0-restore.bat
│ │ ├── _01-add_migrations.cmd
│ │ ├── _02-dotnet_run.bat
│ │ └── appsettings.json
│ ├── Issue125EF5x
│ │ ├── App_Data
│ │ │ └── .gitkeep
│ │ ├── DataLayer
│ │ │ ├── ApplicationDbContext.cs
│ │ │ └── MsSqlContextFactory.cs
│ │ ├── EFServiceProvider.cs
│ │ ├── Entities
│ │ │ └── Person.cs
│ │ ├── Issue125EF5x.csproj
│ │ ├── Migrations
│ │ │ ├── 20210509052521_V2021_05_09_0954.Designer.cs
│ │ │ ├── 20210509052521_V2021_05_09_0954.cs
│ │ │ └── ApplicationDbContextModelSnapshot.cs
│ │ ├── Program.cs
│ │ ├── _0-restore.bat
│ │ ├── _01-add_migrations.cmd
│ │ ├── _02-dotnet_run.bat
│ │ └── appsettings.json
│ ├── Issue12MySQL
│ │ ├── DataLayer
│ │ │ ├── ApplicationDbContext.cs
│ │ │ └── MySQLContextFactory.cs
│ │ ├── EFServiceProvider.cs
│ │ ├── Entities
│ │ │ └── Person.cs
│ │ ├── Issue12MySQL.csproj
│ │ ├── Migrations
│ │ │ ├── 20210712051023_V2021_07_12_0939.Designer.cs
│ │ │ ├── 20210712051023_V2021_07_12_0939.cs
│ │ │ └── ApplicationDbContextModelSnapshot.cs
│ │ ├── Program.cs
│ │ ├── _0-restore.bat
│ │ ├── _01-add_migrations.cmd
│ │ ├── _02-dotnet_run.bat
│ │ └── appsettings.json
│ ├── Issue12PostgreSql
│ │ ├── DataLayer
│ │ │ ├── ApplicationDbContext.cs
│ │ │ └── NpgSqlContextFactory.cs
│ │ ├── EFServiceProvider.cs
│ │ ├── Entities
│ │ │ └── Person.cs
│ │ ├── Issue12PostgreSql.csproj
│ │ ├── Migrations
│ │ │ ├── 20231017160021_V2023_10_17_1929.Designer.cs
│ │ │ ├── 20231017160021_V2023_10_17_1929.cs
│ │ │ └── ApplicationDbContextModelSnapshot.cs
│ │ ├── Program.cs
│ │ ├── _0-restore.bat
│ │ ├── _01-add_migrations.cmd
│ │ ├── _02-dotnet_run.bat
│ │ └── appsettings.json
│ ├── Issue154
│ │ ├── App_Data
│ │ │ └── .gitkeep
│ │ ├── DataLayer
│ │ │ ├── ApplicationDbContext.cs
│ │ │ └── SqliteContextFactory.cs
│ │ ├── EFServiceProvider.cs
│ │ ├── Entities
│ │ │ └── Person.cs
│ │ ├── Issue154.csproj
│ │ ├── Migrations
│ │ │ ├── 20220318153843_V2022_03_18_1908.Designer.cs
│ │ │ ├── 20220318153843_V2022_03_18_1908.cs
│ │ │ └── ApplicationDbContextModelSnapshot.cs
│ │ ├── Program.cs
│ │ ├── _0-restore.bat
│ │ ├── _01-add_migrations.cmd
│ │ ├── _02-dotnet_run.bat
│ │ └── appsettings.json
│ ├── Issue192
│ │ ├── App_Data
│ │ │ └── .gitkeep
│ │ ├── DataLayer
│ │ │ ├── ApplicationDbContext.cs
│ │ │ └── MsSqlContextFactory.cs
│ │ ├── EFServiceProvider.cs
│ │ ├── Entities
│ │ │ └── Person.cs
│ │ ├── Issue192.csproj
│ │ ├── Migrations
│ │ │ ├── 20230110072026_V2023_01_10_1050.Designer.cs
│ │ │ ├── 20230110072026_V2023_01_10_1050.cs
│ │ │ └── ApplicationDbContextModelSnapshot.cs
│ │ ├── Program.cs
│ │ ├── _0-restore.bat
│ │ ├── _01-add_migrations.cmd
│ │ ├── _02-dotnet_run.bat
│ │ └── appsettings.json
│ ├── Issue4SpatialType
│ │ ├── App_Data
│ │ │ └── .gitkeep
│ │ ├── DataLayer
│ │ │ ├── ApplicationDbContext.cs
│ │ │ └── MsSqlContextFactory.cs
│ │ ├── EFServiceProvider.cs
│ │ ├── Entities
│ │ │ ├── Person.cs
│ │ │ └── Product.cs
│ │ ├── Issue4SpatialType.csproj
│ │ ├── Migrations
│ │ │ ├── 20200304112357_V2020_03_04_1453.Designer.cs
│ │ │ ├── 20200304112357_V2020_03_04_1453.cs
│ │ │ └── ApplicationDbContextModelSnapshot.cs
│ │ ├── Program.cs
│ │ ├── _0-restore.bat
│ │ ├── _01-add_migrations.cmd
│ │ ├── _02-dotnet_run.bat
│ │ └── appsettings.json
│ └── Issue9SQLiteInt32
│ │ ├── App_Data
│ │ ├── .gitkeep
│ │ └── TestDb.sqlite
│ │ ├── DataLayer
│ │ ├── ApplicationDbContext.cs
│ │ └── SqliteContextFactory.cs
│ │ ├── EFServiceProvider.cs
│ │ ├── Entities
│ │ └── Person.cs
│ │ ├── Issue9SQLiteInt32.csproj
│ │ ├── Migrations
│ │ ├── 20200322180442_V2020_03_22_2234.Designer.cs
│ │ ├── 20200322180442_V2020_03_22_2234.cs
│ │ ├── 20200322194455_V2020_03_23_0014.Designer.cs
│ │ ├── 20200322194455_V2020_03_23_0014.cs
│ │ └── ApplicationDbContextModelSnapshot.cs
│ │ ├── Program.cs
│ │ ├── _0-restore.bat
│ │ ├── _01-add_migrations.cmd
│ │ ├── _02-dotnet_run.bat
│ │ └── appsettings.json
│ └── redis-64.3.0.503
│ ├── redis-benchmark.exe
│ ├── redis-check-aof.exe
│ ├── redis-check-dump.exe
│ ├── redis-cli.exe
│ ├── redis-server.exe
│ ├── redis.windows-service.conf
│ ├── redis.windows.conf
│ └── ref.txt
├── tag-it.bat
└── update-dependencies.bat
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: ['https://www.coffeete.ir/vnasiri', 'https://www.buymeacoffee.com/vahidn']
13 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | # PR Checklist
2 |
3 | Please check if your PR fulfills the following requirements:
4 |
5 | - [ ] The commit message follows [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
6 | - [ ] Tests for the changes have been added (for bug fixes / features)
7 | - [ ] Docs have been added / updated (for bug fixes / features)
8 |
9 | ## PR Type
10 |
11 | What kind of change does this PR introduce?
12 |
13 |
14 |
15 | - [ ] Bugfix
16 | - [ ] Feature
17 | - [ ] Refactoring (no functional changes, no api changes)
18 | - [ ] Other... Please describe:
19 |
20 | ## What is the current behavior?
21 |
22 |
23 |
24 | Closes #
25 |
26 | ## What is the new behavior?
27 |
28 | ## Does this PR introduce a breaking change?
29 |
30 | - [ ] Yes
31 | - [ ] No
32 |
33 |
34 |
35 | ## Other information
36 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: nuget
4 | directory: "/"
5 | schedule:
6 | interval: "daily"
7 | open-pull-requests-limit: 10
8 | groups:
9 | tests:
10 | patterns: ["*"]
11 | update-types: ["minor", "patch"]
12 | - package-ecosystem: github-actions
13 | directory: "/"
14 | schedule:
15 | interval: "daily"
16 | open-pull-requests-limit: 10
17 | - package-ecosystem: dotnet-sdk
18 | directory: "/"
19 | schedule:
20 | interval: "daily"
21 | open-pull-requests-limit: 10
22 |
--------------------------------------------------------------------------------
/.github/issue_template.md:
--------------------------------------------------------------------------------
1 | # Summary of the issue
2 |
3 |
4 |
5 | ## Environment
6 |
7 | ```
8 | .NET (Core) SDK version:
9 | Microsoft.EntityFrameworkCore version:
10 | EFCoreSecondLevelCacheInterceptor version:
11 | Database: (e.g. SQL Server, SQLite, etc.)
12 | Cache provider: (e.g. in-memory, redis, etc.)
13 | ```
14 |
15 | ## Example code/Steps to reproduce:
16 |
17 | ```
18 | paste your core code
19 | ```
20 |
21 | ## Output:
22 |
23 | ```
24 | Exception message:
25 | Full Stack trace:
26 | ```
27 |
28 |
--------------------------------------------------------------------------------
/.github/lock.yml:
--------------------------------------------------------------------------------
1 | daysUntilLock: 90
2 |
3 | skipCreatedBefore: false
4 |
5 | exemptLabels: []
6 |
7 | lockLabel: false
8 |
9 | lockComment: >
10 | This thread has been automatically locked since there has not been
11 | any recent activity after it was closed. Please open a new issue for
12 | related problems.
13 |
14 | setLockReason: true
15 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: .NET Core Build
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: windows-2019
9 |
10 | steps:
11 | - uses: actions/checkout@v4
12 | - name: Setup .NET Core
13 | uses: actions/setup-dotnet@v4
14 | with:
15 | dotnet-version: 9.0.x
16 | - name: Build EFCoreSecondLevelCacheInterceptor lib
17 | run: dotnet build ./src/EFCoreSecondLevelCacheInterceptor/EFCoreSecondLevelCacheInterceptor.csproj --configuration Release
18 |
19 | - name: Run EFCoreSecondLevelCacheInterceptor lib unit tests
20 | run: dotnet test ./src/Tests/EFCoreSecondLevelCacheInterceptor.UnitTests/EFCoreSecondLevelCacheInterceptor.UnitTests.csproj --logger "console;verbosity=detailed"
21 |
22 | - name: Build EFCoreSecondLevelCacheInterceptor.CacheManager.Core lib
23 | run: dotnet build ./src/EFCoreSecondLevelCacheInterceptor.CacheManager.Core/EFCoreSecondLevelCacheInterceptor.CacheManager.Core.csproj --configuration Release
24 |
25 | - name: Build EFCoreSecondLevelCacheInterceptor.EasyCaching.Core lib
26 | run: dotnet build ./src/EFCoreSecondLevelCacheInterceptor.EasyCaching.Core/EFCoreSecondLevelCacheInterceptor.EasyCaching.Core.csproj --configuration Release
27 |
28 | - name: Build EFCoreSecondLevelCacheInterceptor.MemoryCache lib
29 | run: dotnet build ./src/EFCoreSecondLevelCacheInterceptor.MemoryCache/EFCoreSecondLevelCacheInterceptor.MemoryCache.csproj --configuration Release
30 |
31 | - name: Build EFCoreSecondLevelCacheInterceptor.FusionCache lib
32 | run: dotnet build ./src/EFCoreSecondLevelCacheInterceptor.FusionCache/EFCoreSecondLevelCacheInterceptor.FusionCache.csproj --configuration Release
33 |
34 | - name: Build EFCoreSecondLevelCacheInterceptor.StackExchange.Redis lib
35 | run: dotnet build ./src/EFCoreSecondLevelCacheInterceptor.StackExchange.Redis/EFCoreSecondLevelCacheInterceptor.StackExchange.Redis.csproj --configuration Release
36 |
37 | - name: Build EFCoreSecondLevelCacheInterceptor.HybridCache lib
38 | run: dotnet build ./src/EFCoreSecondLevelCacheInterceptor.HybridCache/EFCoreSecondLevelCacheInterceptor.HybridCache.csproj --configuration Release
39 |
40 | - name: Push Package to NuGet.org
41 | if: github.event_name == 'push'
42 | run: dotnet nuget push **\*.nupkg -k ${{ secrets.NUGET_API_KEY }} -s https://api.nuget.org/v3/index.json --skip-duplicate
43 |
--------------------------------------------------------------------------------
/.github/workflows/codeql/codeql-config.yml:
--------------------------------------------------------------------------------
1 | name: "Security and Quality"
2 |
3 | queries:
4 | - uses: security-and-quality
5 |
6 | paths-ignore:
7 | - '**/*.g.cs'
8 | - '**/*.g.i.cs'
9 |
10 | query-filters:
11 | - exclude:
12 | id: cs/useless-if-statement
13 | - exclude:
14 | id: cs/empty-block
15 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "9.0.300",
4 | "rollForward": "latestMajor",
5 | "allowPrerelease": true
6 | }
7 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.CacheManager.Core/EFCacheManagerCoreProviderOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace EFCoreSecondLevelCacheInterceptor;
4 |
5 | ///
6 | /// Defines EFCoreSecondLevel's Options
7 | ///
8 | public static class EFCacheManagerCoreProviderOptions
9 | {
10 | ///
11 | /// Introduces the built-in `CacheManagerCoreProvider` to be used as the CacheProvider.
12 | ///
13 | public static EFCoreSecondLevelCacheOptions UseCacheManagerCoreProvider(this EFCoreSecondLevelCacheOptions options)
14 | {
15 | if (options == null)
16 | {
17 | throw new ArgumentNullException(nameof(options));
18 | }
19 |
20 | options.Settings.CacheProvider = typeof(EFCacheManagerCoreProvider);
21 |
22 | return options;
23 | }
24 |
25 | ///
26 | /// Introduces the built-in `CacheManagerCoreProvider` to be used as the CacheProvider.
27 | /// If you specify the `Cacheable()` method options, its setting will override this global setting.
28 | ///
29 | ///
30 | /// Defines the expiration mode of the cache items globally.
31 | /// The expiration timeout.
32 | public static EFCoreSecondLevelCacheOptions UseCacheManagerCoreProvider(this EFCoreSecondLevelCacheOptions options,
33 | CacheExpirationMode expirationMode,
34 | TimeSpan? timeout = null)
35 | {
36 | if (options == null)
37 | {
38 | throw new ArgumentNullException(nameof(options));
39 | }
40 |
41 | options.Settings.CacheProvider = typeof(EFCacheManagerCoreProvider);
42 |
43 | options.Settings.CachableQueriesOptions = new CachableQueriesOptions
44 | {
45 | ExpirationMode = expirationMode,
46 | Timeout = timeout,
47 | IsActive = true
48 | };
49 |
50 | return options;
51 | }
52 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.CacheManager.Core/_build.cmd:
--------------------------------------------------------------------------------
1 | dotnet build
2 | pause
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.EasyCaching.Core/_build.cmd:
--------------------------------------------------------------------------------
1 | dotnet build
2 | pause
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.FusionCache/EFCoreSecondLevelCacheInterceptor.FusionCache.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Entity Framework Core Second Level Caching Library.
4 | Vahid Nasiri
5 | net9.0;net8.0;
6 | true
7 | EFCoreSecondLevelCacheInterceptor.FusionCache
8 | EFCoreSecondLevelCacheInterceptor.FusionCache
9 | EntityFramework;Cache;Caching;SecondLevelCache;EFCore;ORM;.NET Core;aspnetcore
10 | https://github.com/VahidN/EFCoreSecondLevelCacheInterceptor
11 | https://github.com/VahidN/EFCoreSecondLevelCacheInterceptor
12 | git
13 | Apache-2.0
14 | false
15 | false
16 | false
17 | true
18 | true
19 | embedded
20 | true
21 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
22 | true
23 | NU5104
24 | README.md
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.FusionCache/EFFusionCacheConfigurationOptions.cs:
--------------------------------------------------------------------------------
1 | namespace EFCoreSecondLevelCacheInterceptor;
2 |
3 | ///
4 | /// Custom FusionCache options.
5 | ///
6 | public class EFFusionCacheConfigurationOptions
7 | {
8 | ///
9 | /// Name of the named cache! If it's not specified, the default cache will be used.
10 | /// It must match the one provided during registration (services.AddFusionCache("__name__")).
11 | ///
12 | public string? NamedCache { set; get; }
13 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.FusionCache/_build.cmd:
--------------------------------------------------------------------------------
1 | dotnet build
2 | pause
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.HybridCache/EFCoreSecondLevelCacheInterceptor.HybridCache.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Entity Framework Core Second Level Caching Library.
4 | Vahid Nasiri
5 | net9.0;net8.0;
6 | true
7 | EFCoreSecondLevelCacheInterceptor.HybridCache
8 | EFCoreSecondLevelCacheInterceptor.HybridCache
9 | EntityFramework;Cache;Caching;SecondLevelCache;EFCore;ORM;.NET Core;aspnetcore
10 | https://github.com/VahidN/EFCoreSecondLevelCacheInterceptor
11 | https://github.com/VahidN/EFCoreSecondLevelCacheInterceptor
12 | git
13 | Apache-2.0
14 | false
15 | false
16 | false
17 | true
18 | true
19 | embedded
20 | true
21 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
22 | true
23 | NU5104
24 | README.md
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.HybridCache/EFHybridCacheProviderOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.DependencyInjection.Extensions;
3 |
4 | namespace EFCoreSecondLevelCacheInterceptor;
5 |
6 | ///
7 | /// Defines EFCoreSecondLevel's Options
8 | ///
9 | public static class EFHybridCacheProviderOptions
10 | {
11 | ///
12 | /// Introduces the `EFHybridCacheProvider` to be used as the CacheProvider.
13 | ///
14 | public static EFCoreSecondLevelCacheOptions UseHybridCacheProvider(this EFCoreSecondLevelCacheOptions options)
15 | {
16 | ArgumentNullException.ThrowIfNull(options);
17 |
18 | options.Settings.Services?.TryAddSingleton();
19 | options.Settings.CacheProvider = typeof(EFHybridCacheProvider);
20 |
21 | return options;
22 | }
23 |
24 | ///
25 | /// Introduces the `EFHybridCacheProvider` to be used as the CacheProvider.
26 | /// If you specify the `Cacheable()` method options, its setting will override this global setting.
27 | ///
28 | ///
29 | /// Defines the expiration mode of the cache items globally.
30 | /// The expiration timeout.
31 | public static EFCoreSecondLevelCacheOptions UseHybridCacheProvider(this EFCoreSecondLevelCacheOptions options,
32 | CacheExpirationMode expirationMode,
33 | TimeSpan? timeout = null)
34 | {
35 | ArgumentNullException.ThrowIfNull(options);
36 |
37 | options.UseHybridCacheProvider();
38 |
39 | options.Settings.CachableQueriesOptions = new CachableQueriesOptions
40 | {
41 | ExpirationMode = expirationMode,
42 | Timeout = timeout,
43 | IsActive = true
44 | };
45 |
46 | return options;
47 | }
48 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.HybridCache/IEFHybridCacheDependenciesStore.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace EFCoreSecondLevelCacheInterceptor;
4 |
5 | ///
6 | /// Provides information about the in-use cache-dependencies
7 | ///
8 | public interface IEFHybridCacheDependenciesStore
9 | {
10 | ///
11 | /// Adds the given tags list to the list of current tags
12 | ///
13 | ///
14 | void AddCacheDependencies(IEnumerable? tags);
15 |
16 | ///
17 | /// Removes the given tags list from the list of current tags
18 | ///
19 | ///
20 | void RemoveCacheDependencies(IEnumerable? tags);
21 |
22 | ///
23 | /// Returns the cached entries added by this library.
24 | ///
25 | ISet GetAllCacheDependencies();
26 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.HybridCache/_build.cmd:
--------------------------------------------------------------------------------
1 | dotnet build
2 | pause
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.MemoryCache/EFMemoryCacheChangeTokenProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.Threading;
4 | using Microsoft.Extensions.Primitives;
5 |
6 | namespace EFCoreSecondLevelCacheInterceptor;
7 |
8 | ///
9 | /// Propagates notifications that a change has occurred.
10 | ///
11 | public class EFMemoryCacheChangeTokenProvider : IMemoryCacheChangeTokenProvider
12 | {
13 | private readonly ConcurrentDictionary _changeTokens;
14 |
15 | ///
16 | /// Propagates notifications that a change has occurred.
17 | ///
18 | public EFMemoryCacheChangeTokenProvider()
19 | => _changeTokens = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
20 |
21 | ///
22 | /// Gets or adds a change notification token.
23 | ///
24 | public IChangeToken GetChangeToken(string key)
25 | => _changeTokens.GetOrAdd(key, _ =>
26 | {
27 | var cancellationTokenSource = new CancellationTokenSource();
28 | var changeToken = new CancellationChangeToken(cancellationTokenSource.Token);
29 |
30 | return new ChangeTokenInfo(changeToken, cancellationTokenSource);
31 | })
32 | .ChangeToken;
33 |
34 | ///
35 | /// Removes a change notification token.
36 | ///
37 | public void RemoveChangeToken(string key)
38 | {
39 | if (_changeTokens.TryRemove(key, out var changeTokenInfo))
40 | {
41 | changeTokenInfo.TokenSource.Cancel();
42 | }
43 | }
44 |
45 | ///
46 | /// Removes all the change notification tokens.
47 | ///
48 | public void RemoveAllChangeTokens()
49 | {
50 | foreach (var item in _changeTokens)
51 | {
52 | RemoveChangeToken(item.Key);
53 | }
54 | }
55 |
56 | private readonly struct ChangeTokenInfo(IChangeToken changeToken, CancellationTokenSource tokenSource)
57 | {
58 | public IChangeToken ChangeToken { get; } = changeToken;
59 |
60 | public CancellationTokenSource TokenSource { get; } = tokenSource;
61 | }
62 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.MemoryCache/EFMemoryCacheProviderOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using Microsoft.Extensions.DependencyInjection.Extensions;
4 |
5 | namespace EFCoreSecondLevelCacheInterceptor;
6 |
7 | ///
8 | /// Defines EFCoreSecondLevel's Options
9 | ///
10 | public static class EFMemoryCacheProviderOptions
11 | {
12 | ///
13 | /// Introduces the built-in `EFMemoryCacheServiceProvider` to be used as the CacheProvider.
14 | ///
15 | public static EFCoreSecondLevelCacheOptions UseMemoryCacheProvider(this EFCoreSecondLevelCacheOptions options)
16 | {
17 | if (options == null)
18 | {
19 | throw new ArgumentNullException(nameof(options));
20 | }
21 |
22 | options.Settings.Services?.AddMemoryCache();
23 | options.Settings.Services?.TryAddSingleton();
24 | options.Settings.CacheProvider = typeof(EFMemoryCacheServiceProvider);
25 |
26 | return options;
27 | }
28 |
29 | ///
30 | /// Introduces the built-in `EFMemoryCacheServiceProvider` to be used as the CacheProvider.
31 | /// If you specify the `Cacheable()` method options, its setting will override this global setting.
32 | ///
33 | ///
34 | /// Defines the expiration mode of the cache items globally.
35 | /// The expiration timeout.
36 | public static EFCoreSecondLevelCacheOptions UseMemoryCacheProvider(this EFCoreSecondLevelCacheOptions options,
37 | CacheExpirationMode expirationMode,
38 | TimeSpan? timeout = null)
39 | {
40 | if (options == null)
41 | {
42 | throw new ArgumentNullException(nameof(options));
43 | }
44 |
45 | options.UseMemoryCacheProvider();
46 |
47 | options.Settings.CachableQueriesOptions = new CachableQueriesOptions
48 | {
49 | ExpirationMode = expirationMode,
50 | Timeout = timeout,
51 | IsActive = true
52 | };
53 |
54 | return options;
55 | }
56 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.MemoryCache/IMemoryCacheChangeTokenProvider.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Primitives;
2 |
3 | namespace EFCoreSecondLevelCacheInterceptor;
4 |
5 | ///
6 | /// Propagates notifications that a change has occurred.
7 | ///
8 | public interface IMemoryCacheChangeTokenProvider
9 | {
10 | ///
11 | /// Gets or adds a change notification token.
12 | ///
13 | IChangeToken GetChangeToken(string key);
14 |
15 | ///
16 | /// Removes a change notification token.
17 | ///
18 | void RemoveChangeToken(string key);
19 |
20 | ///
21 | /// Removes all the change notification tokens.
22 | ///
23 | void RemoveAllChangeTokens();
24 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.MemoryCache/_build.cmd:
--------------------------------------------------------------------------------
1 | dotnet build
2 | pause
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.StackExchange.Redis/EFMessagePackDBNullFormatter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using MessagePack;
3 | using MessagePack.Formatters;
4 |
5 | namespace EFCoreSecondLevelCacheInterceptor;
6 |
7 | ///
8 | /// The contract for serialization of some specific type.
9 | ///
10 | public class EFMessagePackDBNullFormatter : IMessagePackFormatter
11 | {
12 | ///
13 | /// DBNullFormatter instance
14 | ///
15 | public static readonly EFMessagePackDBNullFormatter Instance = new();
16 |
17 | private EFMessagePackDBNullFormatter()
18 | {
19 | }
20 |
21 | ///
22 | public void Serialize(ref MessagePackWriter writer, DBNull? value, MessagePackSerializerOptions options)
23 | => writer.WriteNil();
24 |
25 | ///
26 | public DBNull Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) => DBNull.Value;
27 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.StackExchange.Redis/EFRedisCacheConfigurationOptions.cs:
--------------------------------------------------------------------------------
1 | using StackExchange.Redis;
2 |
3 | namespace EFCoreSecondLevelCacheInterceptor;
4 |
5 | ///
6 | /// The options relevant to a set of redis connections.
7 | ///
8 | public class EFRedisCacheConfigurationOptions
9 | {
10 | ///
11 | /// The options relevant to a set of redis connections.
12 | ///
13 | public ConfigurationOptions? ConfigurationOptions { set; get; }
14 |
15 | ///
16 | /// Redis ConnectionString
17 | ///
18 | public string? RedisConnectionString { set; get; }
19 |
20 | ///
21 | /// Enables MessagePackCompression.Lz4BlockArray
22 | ///
23 | public bool EnableCompression { set; get; }
24 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.StackExchange.Redis/IEFDataSerializer.cs:
--------------------------------------------------------------------------------
1 | namespace EFCoreSecondLevelCacheInterceptor;
2 |
3 | ///
4 | /// High-Level API of a Serializer.
5 | ///
6 | public interface IEFDataSerializer
7 | {
8 | ///
9 | /// Serializes a given value with the specified buffer writer.
10 | ///
11 | byte[] Serialize(T? obj);
12 |
13 | ///
14 | /// Deserializes a value of a given type from a sequence of bytes.
15 | ///
16 | T? Deserialize(byte[]? data);
17 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor.StackExchange.Redis/_build.cmd:
--------------------------------------------------------------------------------
1 | dotnet build
2 | pause
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | [assembly: CLSCompliant(false)]
4 |
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/CachableQueriesOptions.cs:
--------------------------------------------------------------------------------
1 | namespace EFCoreSecondLevelCacheInterceptor;
2 |
3 | ///
4 | /// Cachable queries Options
5 | ///
6 | public class CachableQueriesOptions : CacheAllQueriesOptions
7 | {
8 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/CacheAllQueriesOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace EFCoreSecondLevelCacheInterceptor;
4 |
5 | ///
6 | /// CacheAllQueries Options
7 | ///
8 | public class CacheAllQueriesOptions
9 | {
10 | ///
11 | /// Defines the expiration mode of the cache item.
12 | ///
13 | public CacheExpirationMode ExpirationMode { set; get; }
14 |
15 | ///
16 | /// The expiration timeout.
17 | ///
18 | public TimeSpan? Timeout { set; get; }
19 |
20 | ///
21 | /// Enables or disables the `CacheAllQueries` feature.
22 | ///
23 | public bool IsActive { set; get; }
24 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/CacheExpirationMode.cs:
--------------------------------------------------------------------------------
1 | namespace EFCoreSecondLevelCacheInterceptor;
2 |
3 | ///
4 | /// Defines the supported expiration modes for cache items.
5 | ///
6 | public enum CacheExpirationMode
7 | {
8 | ///
9 | /// Defines absolute expiration. The item will expire after the expiration timeout.
10 | ///
11 | Absolute,
12 |
13 | ///
14 | /// Defines sliding expiration. The expiration timeout will be refreshed on every access.
15 | ///
16 | Sliding,
17 |
18 | ///
19 | /// If you do not specify an absolute and/or sliding expiration, then the item will `theoretically` remain cached
20 | /// indefinitely.
21 | ///
22 | NeverRemove
23 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/CacheSpecificQueriesOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace EFCoreSecondLevelCacheInterceptor;
5 |
6 | ///
7 | /// CacheAllQueries Options
8 | ///
9 | ///
10 | /// CacheAllQueries Options
11 | ///
12 | public class CacheSpecificQueriesOptions(IList? entityTypes) : CacheAllQueriesOptions
13 | {
14 | ///
15 | /// Given entity types to cache
16 | ///
17 | public IList? EntityTypes { get; } = entityTypes;
18 |
19 | ///
20 | /// How should we determine which tables should be cached?
21 | ///
22 | public TableNameComparison TableNameComparison { set; get; }
23 |
24 | ///
25 | /// How should we determine which tables should be cached?
26 | ///
27 | public TableTypeComparison TableTypeComparison { set; get; }
28 |
29 | ///
30 | /// Given table names to cache
31 | ///
32 | public IEnumerable? TableNames { set; get; }
33 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/CacheableEventId.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.EntityFrameworkCore;
2 | using Microsoft.Extensions.Logging;
3 |
4 | namespace EFCoreSecondLevelCacheInterceptor;
5 |
6 | ///
7 | /// Event IDs for events that correspond to messages logged to an ILogger
8 | ///
9 | public static class CacheableEventId
10 | {
11 | ///
12 | /// The lower-bound for event IDs used by any Entity Framework or provider code.
13 | ///
14 | public const int CacheableBaseId = 100_000;
15 |
16 | private static readonly string _queryPrefix = $"{DbLoggerCategory.Query.Name}.";
17 |
18 | ///
19 | /// A query result is returned from cache.
20 | ///
21 | public static readonly EventId CacheHit = MakeQueryId(CacheableLogEventId.CacheHit);
22 |
23 | ///
24 | /// A query result is stored by the cache.
25 | ///
26 | public static readonly EventId QueryResultCached = MakeQueryId(CacheableLogEventId.QueryResultCached);
27 |
28 | ///
29 | /// A query result is removed from the cache.
30 | ///
31 | public static readonly EventId QueryResultInvalidated = MakeQueryId(CacheableLogEventId.QueryResultInvalidated);
32 |
33 | private static EventId MakeQueryId(CacheableLogEventId id)
34 | => new((int)id, _queryPrefix + id);
35 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/CacheableLogEventId.cs:
--------------------------------------------------------------------------------
1 | namespace EFCoreSecondLevelCacheInterceptor;
2 |
3 | ///
4 | /// Event IDs of the internal logged messages of the library
5 | ///
6 | public enum CacheableLogEventId
7 | {
8 | ///
9 | /// It's not used
10 | ///
11 | None,
12 |
13 | ///
14 | /// The query result is returned from the cache.
15 | ///
16 | CacheHit = CacheableEventId.CacheableBaseId,
17 |
18 | ///
19 | /// The query result is stored in the cache.
20 | ///
21 | QueryResultCached,
22 |
23 | ///
24 | /// The query result was removed from the cache.
25 | ///
26 | QueryResultInvalidated,
27 |
28 | ///
29 | /// The query result was not cached due to some predefined setting.
30 | ///
31 | CachingSkipped,
32 |
33 | ///
34 | /// The query result was not remove from the cached due to some predefined setting.
35 | ///
36 | InvalidationSkipped,
37 |
38 | ///
39 | /// It will be fired when the current interceptor is instantiated for the first time.
40 | ///
41 | CachingSystemStarted,
42 |
43 | ///
44 | /// An exception has been occured
45 | ///
46 | CachingError,
47 |
48 | ///
49 | /// The query result was overwritten by the interceptor for the cache
50 | ///
51 | QueryResultSuppressed,
52 |
53 | ///
54 | /// It will be fired when the cache dependencies if the current query are calculated
55 | ///
56 | CacheDependenciesCalculated,
57 |
58 | ///
59 | /// It will be fired when the cache policy of the current query is calculated
60 | ///
61 | CachePolicyCalculated
62 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/EFCacheInvalidationInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace EFCoreSecondLevelCacheInterceptor;
5 |
6 | ///
7 | /// Represents some information about the current cache invalidation event
8 | ///
9 | public class EFCacheInvalidationInfo
10 | {
11 | ///
12 | /// Invalidated all the cache entries due to early expiration of a root cache key
13 | ///
14 | public bool ClearAllCachedEntries { set; get; }
15 |
16 | ///
17 | /// Determines which entities are used in this LINQ query.
18 | /// This array will be used to invalidate the related cache of all related queries automatically.
19 | /// If `ClearAllCachedEntries` is set to true, this property will be ignored.
20 | ///
21 | public ISet CacheDependencies { set; get; } = new HashSet(StringComparer.OrdinalIgnoreCase);
22 |
23 | ///
24 | /// Defines a mechanism for retrieving a service object.
25 | /// For instance, you can create an ILoggerFactory by using it.
26 | ///
27 | public IServiceProvider ServiceProvider { set; get; } = default!;
28 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/EFCacheKey.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace EFCoreSecondLevelCacheInterceptor;
5 |
6 | ///
7 | /// Stores information of the computed key of the input LINQ query.
8 | ///
9 | ///
10 | /// Stores information of the computed key of the input LINQ query.
11 | ///
12 | public class EFCacheKey(ISet cacheDependencies)
13 | {
14 | ///
15 | /// Hash of the input LINQ query's computed key.
16 | ///
17 | public string KeyHash { set; get; } = default!;
18 |
19 | ///
20 | /// Type of DbContext.
21 | ///
22 | public Type? DbContext { get; set; }
23 |
24 | ///
25 | /// Determines which entities are used in this LINQ query.
26 | /// This array will be used to invalidate the related cache of all related queries automatically.
27 | ///
28 | public ISet CacheDependencies { get; } = cacheDependencies;
29 |
30 | ///
31 | /// Equals
32 | ///
33 | ///
34 | public override bool Equals(object? obj)
35 | {
36 | if (obj is not EFCacheKey efCacheKey)
37 | {
38 | return false;
39 | }
40 |
41 | return string.Equals(KeyHash, efCacheKey.KeyHash, StringComparison.Ordinal) &&
42 | DbContext == efCacheKey.DbContext;
43 | }
44 |
45 | ///
46 | /// GetHashCode
47 | ///
48 | public override int GetHashCode()
49 | {
50 | unchecked
51 | {
52 | var hash = 17;
53 |
54 | return hash * 23 + KeyHash.GetHashCode(StringComparison.Ordinal) +
55 | (DbContext == null ? 0 : DbContext.Name.GetHashCode(StringComparison.Ordinal));
56 | }
57 | }
58 |
59 | ///
60 | /// ToString
61 | ///
62 | public override string ToString()
63 | => $"KeyHash: {KeyHash}, DbContext: {DbContext?.Name}, CacheDependencies: {string.Join(separator: ", ", CacheDependencies)}.";
64 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/EFCacheKeyPrefixProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.Extensions.Options;
3 |
4 | namespace EFCoreSecondLevelCacheInterceptor;
5 |
6 | ///
7 | /// A custom cache key prefix provider for EF queries.
8 | ///
9 | public class EFCacheKeyPrefixProvider : IEFCacheKeyPrefixProvider
10 | {
11 | private readonly EFCoreSecondLevelCacheSettings _cacheSettings;
12 | private readonly IServiceProvider _serviceProvider;
13 |
14 | ///
15 | /// A custom cache key prefix provider for EF queries.
16 | ///
17 | public EFCacheKeyPrefixProvider(IServiceProvider serviceProvider,
18 | IOptions cacheSettings)
19 | {
20 | _serviceProvider = serviceProvider;
21 | if (cacheSettings == null)
22 | {
23 | throw new ArgumentNullException(nameof(cacheSettings));
24 | }
25 |
26 | _cacheSettings = cacheSettings.Value;
27 | }
28 |
29 | ///
30 | /// returns the current provided cache key prefix
31 | ///
32 | public string GetCacheKeyPrefix() => _cacheSettings.CacheKeyPrefixSelector is not null
33 | ? _cacheSettings.CacheKeyPrefixSelector(_serviceProvider)
34 | : _cacheSettings.CacheKeyPrefix;
35 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/EFCachePolicyContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace EFCoreSecondLevelCacheInterceptor;
5 |
6 | ///
7 | /// Provides information about the currently executing query
8 | ///
9 | public class EFCachePolicyContext
10 | {
11 | ///
12 | /// The currently executing query
13 | ///
14 | public string CommandText { set; get; } = null!;
15 |
16 | ///
17 | /// The associated currently executing query's table names.
18 | ///
19 | public ISet CommandTableNames { set; get; } = new SortedSet(StringComparer.OrdinalIgnoreCase);
20 |
21 | ///
22 | /// The associated currently executing query's entity types.
23 | ///
24 | public IList CommandEntityTypes { set; get; } = [];
25 |
26 | ///
27 | /// Is `insert`, `update` or `delete`?
28 | ///
29 | public bool IsCrudCommand { set; get; }
30 |
31 | ///
32 | /// The currently executing query's EFCachePolicy value, before being possibly altered by calling
33 | /// `OverrideCachePolicy()` method.
34 | ///
35 | public EFCachePolicy? CommandCachePolicy { set; get; }
36 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/EFCacheableLogEvent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace EFCoreSecondLevelCacheInterceptor;
4 |
5 | ///
6 | /// Provides information about the current logged event
7 | ///
8 | public class EFCacheableLogEvent
9 | {
10 | ///
11 | /// Event IDs of the internal logged messages of the library
12 | ///
13 | public CacheableLogEventId EventId { set; get; }
14 |
15 | ///
16 | /// The provides logged message
17 | ///
18 | public string Message { set; get; } = default!;
19 |
20 | ///
21 | /// The related SQL Command
22 | ///
23 | public string CommandText { set; get; } = default!;
24 |
25 | ///
26 | /// Stores information of the computed key of the input LINQ query.
27 | ///
28 | public EFCacheKey? EFCacheKey { set; get; }
29 |
30 | ///
31 | /// Defines a mechanism for retrieving a service object.
32 | /// For instance, you can create an ILoggerFactory by using it.
33 | ///
34 | public IServiceProvider ServiceProvider { set; get; } = default!;
35 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/EFCachedData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.Serialization;
3 |
4 | namespace EFCoreSecondLevelCacheInterceptor;
5 |
6 | ///
7 | /// Cached Data
8 | ///
9 | [Serializable]
10 | [DataContract]
11 | public class EFCachedData
12 | {
13 | ///
14 | /// DbDataReader's result.
15 | ///
16 | [DataMember]
17 | public EFTableRows? TableRows { get; set; }
18 |
19 | ///
20 | /// DbDataReader's NonQuery result.
21 | ///
22 | [DataMember]
23 | public int NonQuery { get; set; }
24 |
25 | ///
26 | /// DbDataReader's Scalar result.
27 | ///
28 | [DataMember]
29 | public object? Scalar { get; set; }
30 |
31 | ///
32 | /// Is result of the query null?
33 | ///
34 | [DataMember]
35 | public bool IsNull { get; set; }
36 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/EFTableColumnInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.Serialization;
3 |
4 | namespace EFCoreSecondLevelCacheInterceptor;
5 |
6 | ///
7 | /// TableColumn's Info
8 | ///
9 | [Serializable]
10 | [DataContract]
11 | public class EFTableColumnInfo
12 | {
13 | ///
14 | /// The column's ordinal.
15 | ///
16 | [DataMember]
17 | public int Ordinal { get; set; }
18 |
19 | ///
20 | /// The column's name.
21 | ///
22 | [DataMember]
23 | public string Name { get; set; } = default!;
24 |
25 | ///
26 | /// The column's DbType Name.
27 | ///
28 | [DataMember]
29 | public string DbTypeName { get; set; } = default!;
30 |
31 | ///
32 | /// The column's Type.
33 | ///
34 | [DataMember]
35 | public string TypeName { get; set; } = default!;
36 |
37 | ///
38 | /// ToString
39 | ///
40 | public override string ToString() =>
41 | $"Ordinal: {Ordinal}, Name: {Name}, DbTypeName: {DbTypeName}, TypeName= {TypeName}.";
42 | }
--------------------------------------------------------------------------------
/src/EFCoreSecondLevelCacheInterceptor/EFTableRow.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.Serialization;
4 |
5 | namespace EFCoreSecondLevelCacheInterceptor;
6 |
7 | ///
8 | /// TableRow's structure
9 | ///
10 | ///
11 | /// TableRow's structure
12 | ///
13 | [Serializable]
14 | [DataContract]
15 | public class EFTableRow(IList