├── .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 values) 16 | { 17 | /// 18 | /// An array of objects with the column values of the current row. 19 | /// 20 | [DataMember(Order = 0)] 21 | public IList Values { get; } = values; 22 | 23 | /// 24 | /// Gets or sets a value that indicates the depth of nesting for the current row. 25 | /// 26 | [DataMember(Order = 1)] 27 | public int Depth { get; set; } 28 | 29 | /// 30 | /// Gets the number of columns in the current row. 31 | /// 32 | [DataMember(Order = 2)] 33 | public int FieldCount => Values.Count; 34 | 35 | /// 36 | /// Returns Values[ordinal] 37 | /// 38 | public object this[int ordinal] => Values[ordinal]; 39 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/IDbCommandIgnoreCachingProcessor.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Common; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace EFCoreSecondLevelCacheInterceptor; 5 | 6 | /// 7 | /// Helps process SecondLevelCacheInterceptor 8 | /// 9 | public interface IDbCommandIgnoreCachingProcessor 10 | { 11 | /// 12 | /// Is this command marked for caching? 13 | /// 14 | (bool ShouldSkipProcessing, EFCachePolicy? CachePolicy) ShouldSkipProcessing(DbCommand? command, 15 | DbContext? context, 16 | CancellationToken cancellationToken = default); 17 | 18 | /// 19 | /// Skip caching of this result based on the provided predicate 20 | /// 21 | bool ShouldSkipCachingResults(string commandText, object value); 22 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/IDbCommandInterceptorProcessor.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Common; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace EFCoreSecondLevelCacheInterceptor; 5 | 6 | /// 7 | /// Helps process SecondLevelCacheInterceptor 8 | /// 9 | public interface IDbCommandInterceptorProcessor 10 | { 11 | /// 12 | /// Reads data from cache or cache it and then returns the result 13 | /// 14 | T ProcessExecutedCommands(DbCommand command, DbContext? context, T result); 15 | 16 | /// 17 | /// Adds command's data to the cache 18 | /// 19 | T ProcessExecutingCommands(DbCommand command, DbContext? context, T result); 20 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/IEFCacheDependenciesProcessor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Data.Common; 3 | using Microsoft.EntityFrameworkCore; 4 | 5 | namespace EFCoreSecondLevelCacheInterceptor; 6 | 7 | /// 8 | /// Cache Dependencies Calculator 9 | /// 10 | public interface IEFCacheDependenciesProcessor 11 | { 12 | /// 13 | /// Finds the related table names of the current query. 14 | /// 15 | SortedSet GetCacheDependencies(DbCommand command, DbContext context, EFCachePolicy cachePolicy); 16 | 17 | /// 18 | /// Finds the related table names of the current query. 19 | /// 20 | SortedSet GetCacheDependencies(EFCachePolicy cachePolicy, SortedSet tableNames, string commandText); 21 | 22 | /// 23 | /// Invalidates all of the cache entries which are dependent on any of the specified root keys. 24 | /// 25 | bool InvalidateCacheDependencies(string commandText, EFCacheKey cacheKey); 26 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/IEFCacheKeyPrefixProvider.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor; 2 | 3 | /// 4 | /// A custom cache key prefix provider for EF queries. 5 | /// 6 | public interface IEFCacheKeyPrefixProvider 7 | { 8 | /// 9 | /// returns the current provided cache key prefix 10 | /// 11 | string GetCacheKeyPrefix(); 12 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/IEFCacheKeyProvider.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Common; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace EFCoreSecondLevelCacheInterceptor; 5 | 6 | /// 7 | /// A custom cache key provider for EF queries. 8 | /// 9 | public interface IEFCacheKeyProvider 10 | { 11 | /// 12 | /// Gets an EF query and returns its hashed key to store in the cache. 13 | /// 14 | /// The EF query. 15 | /// DbContext is a combination of the Unit Of Work and Repository patterns. 16 | /// determines the Expiration time of the cache. 17 | /// Information of the computed key of the input LINQ query. 18 | EFCacheKey GetEFCacheKey(DbCommand command, DbContext context, EFCachePolicy cachePolicy); 19 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/IEFCachePolicyParser.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor; 2 | 3 | /// 4 | /// EFCachePolicy Parser Utils 5 | /// 6 | public interface IEFCachePolicyParser 7 | { 8 | /// 9 | /// Converts the `commandText` to an instance of `EFCachePolicy` 10 | /// 11 | (EFCachePolicy? CachePolicy, bool ShouldSkipCaching) GetEFCachePolicy(string commandText, 12 | IList allEntityTypes); 13 | 14 | /// 15 | /// Does `commandText` contain EFCachePolicyTagPrefix? 16 | /// 17 | bool HasEFCachePolicy(string commandText); 18 | 19 | /// 20 | /// Removes the EFCachePolicy line from the commandText 21 | /// 22 | string RemoveEFCachePolicyTag(string commandText); 23 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/IEFCacheServiceCheck.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor; 2 | 3 | /// 4 | /// Is the configured cache provider online? 5 | /// 6 | public interface IEFCacheServiceCheck 7 | { 8 | /// 9 | /// Is the configured cache services online and available? Can we use it without any problem? 10 | /// 11 | bool IsCacheServiceAvailable(); 12 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/IEFCacheServiceProvider.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor; 2 | 3 | /// 4 | /// Cache Service Provider Contract. 5 | /// 6 | public interface IEFCacheServiceProvider 7 | { 8 | /// 9 | /// Removes the cached entries added by this library. 10 | /// 11 | void ClearAllCachedEntries(); 12 | 13 | /// 14 | /// Gets a cached entry by key. 15 | /// 16 | /// key to find 17 | /// cached value 18 | /// Defines the expiration mode of the cache item. 19 | EFCachedData? GetValue(EFCacheKey cacheKey, EFCachePolicy cachePolicy); 20 | 21 | /// 22 | /// Adds a new item to the cache. 23 | /// 24 | /// key 25 | /// value 26 | /// Defines the expiration mode of the cache item. 27 | void InsertValue(EFCacheKey cacheKey, EFCachedData? value, EFCachePolicy cachePolicy); 28 | 29 | /// 30 | /// Invalidates all the cache entries which are dependent on any of the specified root keys. 31 | /// 32 | /// Stores information of the computed key of the input LINQ query. 33 | void InvalidateCacheDependencies(EFCacheKey cacheKey); 34 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/IEFDebugLogger.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace EFCoreSecondLevelCacheInterceptor; 4 | 5 | /// 6 | /// Formats and writes a debug log message. 7 | /// 8 | public interface IEFDebugLogger 9 | { 10 | /// 11 | /// Determines whether the debug logger is enabled. 12 | /// 13 | bool IsLoggerEnabled { get; } 14 | 15 | /// 16 | /// If you set DisableLogging to false, this delegate will give you the internal caching events of the library. 17 | /// 18 | void NotifyCacheableEvent(CacheableLogEventId eventId, string message, string commandText, EFCacheKey? efCacheKey); 19 | 20 | /// 21 | /// Represents some information about the current cache invalidation event 22 | /// 23 | void NotifyCacheInvalidation(bool clearAllCachedEntries, ISet cacheDependencies); 24 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/IEFHashProvider.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor; 2 | 3 | /// 4 | /// A hash provider contract 5 | /// 6 | public interface IEFHashProvider 7 | { 8 | /// 9 | /// Computes the Hash of the input string. 10 | /// 11 | /// the input string 12 | /// Hash 13 | ulong ComputeHash(string data); 14 | 15 | /// 16 | /// Computes the hash of the input array. 17 | /// 18 | /// the input array 19 | /// Hash 20 | ulong ComputeHash(byte[] data); 21 | 22 | /// 23 | /// Computes the hash of the input byte array. 24 | /// 25 | /// the input byte array 26 | /// start offset 27 | /// length 28 | /// initial seed 29 | /// Hash 30 | ulong ComputeHash(byte[] data, int offset, int len, uint seed); 31 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/IEFSqlCommandsProcessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Microsoft.EntityFrameworkCore; 4 | 5 | namespace EFCoreSecondLevelCacheInterceptor; 6 | 7 | /// 8 | /// SqlCommands Utils 9 | /// 10 | public interface IEFSqlCommandsProcessor 11 | { 12 | /// 13 | /// Extracts the table names of an SQL command. 14 | /// 15 | SortedSet GetSqlCommandTableNames(string commandText); 16 | 17 | /// 18 | /// Extracts the entity types of an SQL command. 19 | /// 20 | IList GetSqlCommandEntityTypes(string commandText, IList allEntityTypes); 21 | 22 | /// 23 | /// Returns all of the given context's table names. 24 | /// 25 | IList GetAllTableNames(DbContext context); 26 | 27 | /// 28 | /// Is `insert`, `update` or `delete`? 29 | /// 30 | bool IsCrudCommand(string text); 31 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/ILockProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace EFCoreSecondLevelCacheInterceptor; 6 | 7 | /// 8 | /// Reader writer locking service 9 | /// 10 | public interface ILockProvider : IDisposable 11 | { 12 | /// 13 | /// Tries to enter the sync lock 14 | /// 15 | IDisposable? Lock(CancellationToken cancellationToken = default); 16 | 17 | /// 18 | /// Tries to enter the async lock 19 | /// 20 | ValueTask LockAsync(CancellationToken cancellationToken = default); 21 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/LockProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using AsyncKeyedLock; 6 | 7 | namespace EFCoreSecondLevelCacheInterceptor; 8 | 9 | /// 10 | /// Reader writer locking service 11 | /// 12 | public sealed class LockProvider : ILockProvider 13 | { 14 | private readonly AsyncNonKeyedLocker _lock = new(); 15 | private readonly TimeSpan _timeout = TimeSpan.FromSeconds(value: 7); 16 | 17 | /// 18 | /// Tries to enter the sync lock 19 | /// 20 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 21 | public IDisposable? Lock(CancellationToken cancellationToken = default) 22 | => _lock.LockOrNull(_timeout, cancellationToken); 23 | 24 | /// 25 | /// Tries to enter the async lock 26 | /// 27 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 28 | public ValueTask LockAsync(CancellationToken cancellationToken = default) 29 | => _lock.LockOrNullAsync(_timeout, cancellationToken); 30 | 31 | /// 32 | /// Disposes the lock 33 | /// 34 | public void Dispose() => _lock.Dispose(); 35 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/SkipCacheSpecificQueriesOptions.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 SkipCacheSpecificQueriesOptions(IList? entityTypes) : CacheAllQueriesOptions 13 | { 14 | /// 15 | /// Given entity types to cache 16 | /// 17 | public IList? EntityTypes { get; } = entityTypes; 18 | 19 | /// 20 | /// Given table names to cache 21 | /// 22 | public IEnumerable? TableNames { set; get; } 23 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/TableEntityInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace EFCoreSecondLevelCacheInterceptor; 4 | 5 | /// 6 | /// A Table's EntityInfo 7 | /// 8 | public class TableEntityInfo 9 | { 10 | /// 11 | /// Gets the CLR class that is used to represent instances of this type. 12 | /// Returns null if the type does not have a corresponding CLR class (known as a shadow type). 13 | /// 14 | public Type ClrType { set; get; } = default!; 15 | 16 | /// 17 | /// The Corresponding table's name. 18 | /// 19 | public string TableName { set; get; } = default!; 20 | 21 | /// 22 | /// Debug info. 23 | /// 24 | public override string ToString() => $"{ClrType}::{TableName}"; 25 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/TableNameComparison.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor; 2 | 3 | /// 4 | /// How should we determine which tables should be cached? 5 | /// 6 | public enum TableNameComparison 7 | { 8 | /// 9 | /// Caches queries containing table names having the specified names. 10 | /// 11 | Contains, 12 | 13 | /// 14 | /// Caches queries containing table names not having the specified names. 15 | /// 16 | DoesNotContain, 17 | 18 | /// 19 | /// Caches queries containing table names end with the specified names. 20 | /// 21 | EndsWith, 22 | 23 | /// 24 | /// Caches queries containing table names which do not end with the specified names. 25 | /// 26 | DoesNotEndWith, 27 | 28 | /// 29 | /// Caches queries containing table names start with the specified names. 30 | /// 31 | StartsWith, 32 | 33 | /// 34 | /// Caches queries containing table names which do not start with the specified names. 35 | /// 36 | DoesNotStartWith, 37 | 38 | /// 39 | /// Caches queries containing table names equal to the specified names exclusively. 40 | /// 41 | ContainsOnly, 42 | 43 | /// 44 | /// Caches queries containing table names equal to every one of the specified names exclusively. 45 | /// 46 | ContainsEvery, 47 | 48 | /// 49 | /// Caches queries containing table names not equal to every one of the specified names exclusively. 50 | /// 51 | DoesNotContainEvery, 52 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/TableTypeComparison.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor; 2 | 3 | /// 4 | /// How should we determine which tables should be cached? 5 | /// 6 | public enum TableTypeComparison 7 | { 8 | /// 9 | /// Caches queries containing table types having the specified types. 10 | /// 11 | Contains, 12 | 13 | /// 14 | /// Caches queries containing table types not having the specified types. 15 | /// 16 | DoesNotContain, 17 | 18 | /// 19 | /// Caches queries containing table types equal to the specified types exclusively. 20 | /// 21 | ContainsOnly, 22 | 23 | /// 24 | /// Caches queries containing table types equal to every one of the specified types exclusively. 25 | /// 26 | ContainsEvery, 27 | 28 | /// 29 | /// Caches queries containing table types not equal to every one of the specified types exclusively. 30 | /// 31 | DoesNotContainEvery, 32 | } -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/_1-dotnet_pack.bat: -------------------------------------------------------------------------------- 1 | dotnet pack -c release 2 | pause -------------------------------------------------------------------------------- /src/EFCoreSecondLevelCacheInterceptor/_2-dotnet_build.bat: -------------------------------------------------------------------------------- 1 | dotnet build 2 | pause -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSample/App_Data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSample/App_Data/.gitkeep -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSample/EFCoreSecondLevelCacheInterceptor.AspNetCoreSample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net9.0 4 | RCS1090 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | all 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSample/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.Hosting; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace EFCoreSecondLevelCacheInterceptor.AspNetCoreSample 7 | { 8 | public class Program 9 | { 10 | public static void Main(string[] args) 11 | { 12 | CreateHostBuilder(args).Build().Run(); 13 | } 14 | 15 | public static IHostBuilder CreateHostBuilder(string[] args) => 16 | Host.CreateDefaultBuilder(args) 17 | .ConfigureWebHostDefaults(webBuilder => 18 | { 19 | webBuilder 20 | .ConfigureLogging((hostingContext, logging) => 21 | { 22 | logging.ClearProviders(); 23 | 24 | logging.AddDebug(); 25 | 26 | if (hostingContext.HostingEnvironment.IsDevelopment()) 27 | { 28 | logging.AddConsole(); 29 | } 30 | logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); 31 | }) 32 | .UseStartup(); 33 | }); 34 | } 35 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSample/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:57399", 7 | "sslPort": 44390 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "EFCoreSecondLevelCacheInterceptor.AspNetCoreSample": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSample/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSample/_1-dotnet_run.bat: -------------------------------------------------------------------------------- 1 | dotnet watch run -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSample/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Debug", 6 | "Microsoft": "Debug", 7 | "Microsoft.Hosting.Lifetime": "Debug" 8 | } 9 | }, 10 | "AllowedHosts": "*", 11 | "ConnectionStrings": { 12 | "ApplicationDbContextConnection": "Server=(localdb)\\mssqllocaldb;Initial Catalog=EFSecondLevelCacheCore2020;AttachDBFilename=%CONTENTROOTPATH%\\App_Data\\EFSecondLevelCacheCore2020.mdf;Trusted_Connection=True;" 13 | }, 14 | "RedisConfiguration": "localhost:6379" 15 | } 16 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar/App_Data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar/App_Data/.gitkeep -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Threading.Tasks; 3 | using Microsoft.AspNetCore.Mvc; 4 | using EFCoreSecondLevelCacheInterceptor.Tests.DataLayer; 5 | using EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Entities; 6 | using Microsoft.EntityFrameworkCore; 7 | using System; 8 | 9 | namespace EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar.Controllers 10 | { 11 | public class HomeController : Controller 12 | { 13 | private readonly ApplicationDbContext _context; 14 | 15 | public HomeController(ApplicationDbContext context) 16 | { 17 | _context = context; 18 | } 19 | 20 | public async Task Index() 21 | { 22 | var param1 = 0; 23 | var post1 = await _context.Set() 24 | .Include(post => post.User) 25 | .Where(post => post.Id > param1) 26 | .OrderBy(post => post.Id) 27 | .Cacheable(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(45)) 28 | .FirstOrDefaultAsync(); 29 | return Json(new { post1.Title, post1.User.Name }); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar/EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net9.0 4 | RCS1090 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | all 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar/Program.cs: -------------------------------------------------------------------------------- 1 | using Lamar.Microsoft.DependencyInjection; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.Hosting; 5 | using Microsoft.Extensions.Logging; 6 | 7 | namespace EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar 8 | { 9 | public class Program 10 | { 11 | public static void Main(string[] args) 12 | { 13 | CreateHostBuilder(args).Build().Run(); 14 | } 15 | 16 | public static IHostBuilder CreateHostBuilder(string[] args) => 17 | Host.CreateDefaultBuilder(args) 18 | // Add Lamar 19 | .UseLamar() 20 | .ConfigureWebHostDefaults(webBuilder => 21 | { 22 | webBuilder 23 | .ConfigureLogging((hostingContext, logging) => 24 | { 25 | logging.ClearProviders(); 26 | logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging")); 27 | logging.AddDebug(); 28 | 29 | if (hostingContext.HostingEnvironment.IsDevelopment()) 30 | { 31 | logging.AddConsole(); 32 | } 33 | }) 34 | .UseStartup(); 35 | }); 36 | } 37 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:21393", 7 | "sslPort": 44355 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar/_1-dotnet_run.bat: -------------------------------------------------------------------------------- 1 | dotnet watch run -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.AspNetCoreSampleWithLamar/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Debug", 6 | "Microsoft": "Debug", 7 | "Microsoft.Hosting.Lifetime": "Debug" 8 | } 9 | }, 10 | "AllowedHosts": "*", 11 | "ConnectionStrings": { 12 | "ApplicationDbContextConnection": "Server=(localdb)\\mssqllocaldb;Initial Catalog=EFSecondLevelCacheCore2020_2;AttachDBFilename=%CONTENTROOTPATH%\\App_Data\\EFSecondLevelCacheCore2020_2.mdf;Trusted_Connection=True;" 13 | }, 14 | "RedisConfiguration": "localhost:6379" 15 | } 16 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.ConsoleSample/EFCoreSecondLevelCacheInterceptor.ConsoleSample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net9.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.ConsoleSample/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Entities; 4 | using EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Utils; 5 | using Microsoft.Extensions.DependencyInjection; 6 | 7 | namespace EFCoreSecondLevelCacheInterceptor.ConsoleSample 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | initDb(); 14 | 15 | EFServiceProvider.RunInContext(context => 16 | { 17 | context.Posts.Add(new Post { Title = "Title 1", UserId = 1 }); 18 | context.SaveChanges(); 19 | 20 | var posts = context.Posts.Cacheable().ToList(); 21 | Console.WriteLine($"Title From DB: {posts.First().Title}"); 22 | 23 | posts = context.Posts.Cacheable().ToList(); 24 | Console.WriteLine($"Title From Cache: {posts.First().Title}"); 25 | }); 26 | } 27 | 28 | private static void initDb() 29 | { 30 | var serviceScope = EFServiceProvider.GetRequiredService(); 31 | serviceScope.Initialize(); 32 | serviceScope.SeedData(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.ConsoleSample/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.ConsoleSample/_1-dotnet_run.bat: -------------------------------------------------------------------------------- 1 | dotnet watch run -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.ConsoleSample/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Debug", 6 | "Microsoft": "Debug", 7 | "Microsoft.Hosting.Lifetime": "Debug" 8 | } 9 | }, 10 | "AllowedHosts": "*", 11 | "ConnectionStrings": { 12 | "ApplicationDbContextConnection": "Server=(localdb)\\mssqllocaldb;Initial Catalog=EFSecondLevelCacheCore2020;AttachDBFilename=%CONTENTROOTPATH%\\App_Data\\EFSecondLevelCacheCore2020.mdf;Trusted_Connection=True;" 13 | }, 14 | "RedisConfiguration": "localhost:6379" 15 | } 16 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.PerformanceTests/BenchmarkTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using BenchmarkDotNet.Attributes; 4 | 5 | namespace EFCoreSecondLevelCacheInterceptor.PerformanceTests 6 | { 7 | public class BenchmarkTests 8 | { 9 | private int _count; 10 | 11 | [Benchmark(Baseline = true)] 12 | public void RunQueryDirectly() 13 | { 14 | EFServiceProvider.RunInContext(db => 15 | { 16 | var products = db.Products.Where(x => x.ProductId > 0).ToList(); 17 | _count = products.Count; 18 | }); 19 | } 20 | 21 | [Benchmark] 22 | public void RunCacheableQueryWithMicrosoftMemoryCache() 23 | { 24 | EFServiceProvider.RunInContext(db => 25 | { 26 | var products = db.Products.Where(x => x.ProductId > 0).Cacheable().ToList(); 27 | _count = products.Count; 28 | }); 29 | } 30 | 31 | [GlobalCleanup] 32 | public void GlobalCleanup() 33 | { 34 | Console.WriteLine($"_count: {_count}"); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.PerformanceTests/EFCoreSecondLevelCacheInterceptor.PerformanceTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net9.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.PerformanceTests/Program.cs: -------------------------------------------------------------------------------- 1 | using EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Utils; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using BenchmarkDotNet.Columns; 4 | using BenchmarkDotNet.Configs; 5 | using BenchmarkDotNet.Jobs; 6 | using BenchmarkDotNet.Running; 7 | using BenchmarkDotNet.Environments; 8 | using Perfolizer.Horology; 9 | 10 | namespace EFCoreSecondLevelCacheInterceptor.PerformanceTests 11 | { 12 | class Program 13 | { 14 | static void Main(string[] args) 15 | { 16 | initDb(); 17 | runBenchmarks(); 18 | } 19 | 20 | private static void runBenchmarks() 21 | { 22 | var config = ManualConfig.Create(DefaultConfig.Instance) 23 | .With(BenchmarkDotNet.Analysers.EnvironmentAnalyser.Default) 24 | .With(BenchmarkDotNet.Exporters.MarkdownExporter.GitHub) 25 | .With(BenchmarkDotNet.Diagnosers.MemoryDiagnoser.Default) 26 | .With(StatisticColumn.Mean) 27 | .With(StatisticColumn.Median) 28 | .With(StatisticColumn.StdDev) 29 | .With(StatisticColumn.OperationsPerSecond) 30 | .With(BaselineRatioColumn.RatioMean) 31 | .With(RankColumn.Arabic) 32 | .With(Job.Default.With(CoreRuntime.Core31) 33 | .WithIterationCount(30) 34 | .WithInvocationCount(16) 35 | .WithIterationTime(TimeInterval.FromSeconds(1000)) 36 | .WithWarmupCount(4) 37 | .WithLaunchCount(1)); 38 | BenchmarkRunner.Run(config); 39 | } 40 | 41 | private static void initDb() 42 | { 43 | var serviceScope = EFServiceProvider.GetRequiredService(); 44 | serviceScope.Initialize(); 45 | serviceScope.SeedData(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.PerformanceTests/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.PerformanceTests/_1-dotnet_run.bat: -------------------------------------------------------------------------------- 1 | dotnet build ..\..\EFCoreSecondLevelCacheInterceptor\EFCoreSecondLevelCacheInterceptor.csproj --configuration Release 2 | dotnet build ..\EFCoreSecondLevelCacheInterceptor.Tests.DataLayer\EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.csproj --configuration Release 3 | dotnet watch run --configuration Release -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.PerformanceTests/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Warning", 5 | "System": "Warning", 6 | "Microsoft": "Warning", 7 | "Microsoft.Hosting.Lifetime": "Warning" 8 | } 9 | }, 10 | "AllowedHosts": "*", 11 | "ConnectionStrings": { 12 | "ApplicationDbContextConnection": "Server=(localdb)\\mssqllocaldb;Initial Catalog=EFSecondLevelCacheCore2020;AttachDBFilename=%CONTENTROOTPATH%\\App_Data\\EFSecondLevelCacheCore2020.mdf;Trusted_Connection=True;" 13 | }, 14 | "RedisConfiguration": "localhost:6379" 15 | } 16 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.PerformanceTests/int-pref.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/EFCoreSecondLevelCacheInterceptor.PerformanceTests/int-pref.png -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net9.0 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | runtime; build; native; contentfiles; analyzers; buildtransitive 13 | all 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/Entities/Blog.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Entities 4 | { 5 | public class Blog 6 | { 7 | public Blog() 8 | { 9 | Posts = new HashSet(); 10 | } 11 | 12 | public int BlogId { get; set; } 13 | public string Url { get; set; } 14 | 15 | public virtual ICollection Posts { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/Entities/DateType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Entities 5 | { 6 | public class DateType 7 | { 8 | public int Id { set; get; } 9 | 10 | public DateTime? AddDate { get; set; } 11 | 12 | public DateTime UpdateDate { get; set; } 13 | 14 | public DateTimeOffset? AddDateValue { get; set; } 15 | 16 | public DateTimeOffset UpdateDateValue { get; set; } 17 | 18 | public TimeSpan? RelativeAddTimeValue { set; get; } 19 | 20 | public TimeSpan RelativeUpdateTimeValue { set; get; } 21 | 22 | [NotMapped] public DateOnly? AddDateOnlyValue { get; set; } 23 | 24 | [NotMapped] public DateOnly UpdateDateOnlyValue { get; set; } 25 | 26 | [NotMapped] public TimeOnly? RelativeAddTimeOnlyValue { set; get; } 27 | 28 | [NotMapped] public TimeOnly RelativeUpdateTimeOnlyValue { set; get; } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/Entities/EngineVersion.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Entities 2 | { 3 | public class EngineVersion 4 | { 5 | public int Id { get; set; } 6 | 7 | public EngineProductVersion Commercial { get; set; } 8 | public EngineProductVersion Retail { get; set; } 9 | } 10 | 11 | public class EngineProductVersion 12 | { 13 | public int Major { get; set; } 14 | public int Minor { get; set; } 15 | public int Revision { get; set; } 16 | public int Patch { get; set; } 17 | 18 | public override string ToString() 19 | => $"{Major}.{Minor}.{Revision}.{Patch}"; 20 | } 21 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/Entities/KeylessEntities.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Entities 2 | { 3 | public class BlogData 4 | { 5 | public int Id { set; get; } 6 | public string SiteUrl { set; get; } 7 | } 8 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/Entities/Post.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Entities 2 | { 3 | public class Post 4 | { 5 | public int Id { get; set; } 6 | public string Title { get; set; } 7 | 8 | public virtual User User { get; set; } 9 | public int UserId { get; set; } 10 | 11 | public int BlogId { get; set; } 12 | public virtual Blog Blog { get; set; } 13 | } 14 | 15 | public class Page : Post 16 | { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/Entities/Product.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Entities 4 | { 5 | public class Product 6 | { 7 | public Product() 8 | { 9 | TagProducts = new HashSet(); 10 | } 11 | 12 | public int ProductId { get; set; } 13 | public string ProductNumber { get; set; } 14 | public string ProductName { get; set; } 15 | public string Notes { get; set; } 16 | public bool IsActive { get; set; } 17 | 18 | public virtual ICollection TagProducts { get; set; } 19 | 20 | public virtual User User { get; set; } 21 | public int UserId { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/Entities/Tag.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Entities 4 | { 5 | public class Tag 6 | { 7 | public Tag() 8 | { 9 | TagProducts = new HashSet(); 10 | } 11 | 12 | public int Id { get; set; } 13 | public string Name { get; set; } 14 | 15 | public virtual ICollection TagProducts { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/Entities/TagProduct.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Entities 2 | { 3 | public class TagProduct 4 | { 5 | public int TagId { get; set; } 6 | public int ProductProductId { get; set; } 7 | 8 | public virtual Product Product { get; set; } 9 | public virtual Tag Tag { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/Entities/User.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Entities 5 | { 6 | public class User 7 | { 8 | public User() 9 | { 10 | Posts = new HashSet(); 11 | Products = new HashSet(); 12 | } 13 | 14 | public int Id { get; set; } 15 | public string Name { get; set; } 16 | public UserStatus UserStatus { get; set; } 17 | 18 | public byte[] ImageData { get; set; } 19 | 20 | public DateTime? AddDate { get; set; } 21 | 22 | public DateTime? UpdateDate { get; set; } 23 | 24 | public long Points { get; set; } 25 | 26 | public bool IsActive { get; set; } 27 | 28 | public byte ByteValue { get; set; } 29 | 30 | public char CharValue { get; set; } 31 | 32 | public DateTimeOffset? DateTimeOffsetValue { get; set; } 33 | 34 | public decimal DecimalValue { get; set; } 35 | 36 | public double DoubleValue { set; get; } 37 | 38 | public float FloatValue { set; get; } 39 | 40 | public Guid GuidValue { set; get; } 41 | 42 | public TimeSpan? TimeSpanValue { set; get; } 43 | 44 | public short ShortValue { set; get; } 45 | 46 | public byte[] ByteArrayValue { get; set; } 47 | 48 | public uint UintValue { set; get; } 49 | 50 | public ulong UlongValue { set; get; } 51 | 52 | public ulong UshortValue { set; get; } 53 | 54 | public virtual ICollection Posts { get; set; } 55 | public virtual ICollection Products { get; set; } 56 | } 57 | 58 | public enum UserStatus 59 | { 60 | Active, 61 | Disabled 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/Migrations/20250106171343_V2025_01_06_2043.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Migrations 6 | { 7 | /// 8 | public partial class V2025_01_06_2043 : Migration 9 | { 10 | /// 11 | protected override void Up(MigrationBuilder migrationBuilder) 12 | { 13 | migrationBuilder.AlterColumn( 14 | name: "post_type", 15 | table: "Posts", 16 | type: "nvarchar(13)", 17 | maxLength: 13, 18 | nullable: false, 19 | oldClrType: typeof(string), 20 | oldType: "nvarchar(max)"); 21 | } 22 | 23 | /// 24 | protected override void Down(MigrationBuilder migrationBuilder) 25 | { 26 | migrationBuilder.AlterColumn( 27 | name: "post_type", 28 | table: "Posts", 29 | type: "nvarchar(max)", 30 | nullable: false, 31 | oldClrType: typeof(string), 32 | oldType: "nvarchar(13)", 33 | oldMaxLength: 13); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/MsSqlContextFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Design; 2 | using Microsoft.Extensions.Configuration; 3 | using System; 4 | using System.IO; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.Logging; 7 | 8 | namespace EFCoreSecondLevelCacheInterceptor.Tests.DataLayer 9 | { 10 | public class MsSqlContextFactory : IDesignTimeDbContextFactory 11 | { 12 | public ApplicationDbContext CreateDbContext(string[] args) 13 | { 14 | var services = new ServiceCollection(); 15 | 16 | services.AddLogging(cfg => cfg.AddConsole().AddDebug()); 17 | 18 | var basePath = Directory.GetCurrentDirectory(); 19 | Console.WriteLine($"Using `{basePath}` as the ContentRootPath"); 20 | var configuration = new ConfigurationBuilder() 21 | .SetBasePath(basePath) 22 | .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) 23 | .Build(); 24 | services.AddSingleton(_ => configuration); 25 | 26 | var connectionString = configuration["ConnectionStrings:ApplicationDbContextConnection"]; 27 | if (connectionString.Contains("%CONTENTROOTPATH%")) 28 | { 29 | connectionString = connectionString.Replace("%CONTENTROOTPATH%", basePath); 30 | } 31 | 32 | services.AddEFSecondLevelCache(options => 33 | options.UseMemoryCacheProvider(CacheExpirationMode.Absolute, TimeSpan.FromMinutes(5))); 34 | 35 | services.AddConfiguredMsSqlDbContext(connectionString); 36 | 37 | return services.BuildServiceProvider().GetService(); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/MsSqlServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace EFCoreSecondLevelCacheInterceptor.Tests.DataLayer 6 | { 7 | public static class MsSqlServiceCollectionExtensions 8 | { 9 | public static IServiceCollection AddConfiguredMsSqlDbContext(this IServiceCollection services, string connectionString) 10 | { 11 | services.AddDbContextPool((serviceProvider, optionsBuilder) => 12 | optionsBuilder 13 | .UseSqlServer( 14 | connectionString, 15 | sqlServerOptionsBuilder => 16 | { 17 | sqlServerOptionsBuilder 18 | .CommandTimeout((int)TimeSpan.FromMinutes(3).TotalSeconds) 19 | .MigrationsAssembly(typeof(MsSqlServiceCollectionExtensions).Assembly.FullName); 20 | }) 21 | .AddInterceptors(serviceProvider.GetRequiredService())); 22 | return services; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/Utils/DBInitialization.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Utils 5 | { 6 | public static class DbInitialization 7 | { 8 | public static void Initialize(this IServiceScopeFactory scopeFactory) 9 | { 10 | using (var serviceScope = scopeFactory.CreateScope()) 11 | { 12 | var context = serviceScope.ServiceProvider.GetRequiredService(); 13 | // Applies any pending migrations for the context to the database. 14 | // Will create the database if it does not already exist. 15 | context.Database.Migrate(); 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/_01-add_migrations.cmd: -------------------------------------------------------------------------------- 1 | For /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c_%%a_%%b) 2 | For /f "tokens=1-2 delims=/:" %%a in ("%TIME: =0%") do (set mytime=%%a%%b) 3 | dotnet tool update --global dotnet-ef --version 9.0.0 4 | dotnet build 5 | dotnet ef migrations --startup-project ../EFCoreSecondLevelCacheInterceptor.AspNetCoreSample/ add V%mydate%_%mytime% --context ApplicationDbContext 6 | pause -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests.DataLayer/_02-update_db.cmd: -------------------------------------------------------------------------------- 1 | dotnet tool update --global dotnet-ef --version 9.0.0 2 | dotnet build 3 | dotnet ef --startup-project ../EFCoreSecondLevelCacheInterceptor.AspNetCoreSample/ database update --context ApplicationDbContext 4 | pause -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests/PerformanceTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | using Microsoft.Extensions.Logging; 5 | using Microsoft.VisualStudio.TestTools.UnitTesting; 6 | 7 | namespace EFCoreSecondLevelCacheInterceptor.Tests 8 | { 9 | [TestClass] 10 | public class PerformanceTests 11 | { 12 | [DataTestMethod] 13 | [DataRow(TestCacheProvider.BuiltInInMemory)] 14 | [DataRow(TestCacheProvider.CacheManagerCoreInMemory)] 15 | [DataRow(TestCacheProvider.CacheManagerCoreRedis)] 16 | [DataRow(TestCacheProvider.EasyCachingCoreInMemory)] 17 | [DataRow(TestCacheProvider.EasyCachingCoreRedis)] 18 | public void PerformanceTest(TestCacheProvider cacheProvider) 19 | { 20 | const decimal loopCount = 1000; 21 | 22 | EFServiceProvider.RunInContext(cacheProvider, LogLevel.Warning, false, (context, debugLoggerProvider) => 23 | { 24 | Stopwatch watch = new Stopwatch(); 25 | watch.Start(); 26 | 27 | // run normal queries 28 | for (int i = 0; i < loopCount; i++) 29 | { 30 | var result = context.Posts.Where(post => post.Id >= 0).Take(100).ToList(); 31 | } 32 | 33 | var uncachedTimeSpan = watch.Elapsed; 34 | 35 | // cache the query result 36 | var posts = context.Posts.Where(post => post.Id >= 0).Take(100).Cacheable().ToList(); 37 | 38 | watch.Restart(); 39 | 40 | // run cached queries 41 | for (int i = 0; i < loopCount; i++) 42 | { 43 | var result = context.Posts.Where(post => post.Id >= 0).Take(100).Cacheable().ToList(); 44 | } 45 | 46 | var cachedTimeSpan = watch.Elapsed; 47 | 48 | var message = $"Average database query duration [+{TimeSpan.FromTicks((long)(uncachedTimeSpan.Ticks / loopCount))}].\n" + 49 | $"Average cache query duration [+{TimeSpan.FromTicks((long)(cachedTimeSpan.Ticks / loopCount))}].\n" + 50 | $"Cached queries are x{(uncachedTimeSpan.Ticks / (decimal)cachedTimeSpan.Ticks) - 1:N2} times faster."; 51 | 52 | Assert.IsTrue(uncachedTimeSpan > cachedTimeSpan, message); 53 | }); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests/Settings/Bootstrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using EFCoreSecondLevelCacheInterceptor.Tests.DataLayer.Utils; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Logging; 5 | using Microsoft.VisualStudio.TestTools.UnitTesting; 6 | 7 | namespace EFCoreSecondLevelCacheInterceptor.Tests; 8 | 9 | [TestClass] 10 | public class Bootstrapper 11 | { 12 | [AssemblyInitialize] 13 | public static void Initialize(TestContext context) 14 | { 15 | clearAllCachedEntries(); 16 | startDb(); 17 | } 18 | 19 | [AssemblyCleanup] 20 | public static void AssemblyCleanup() 21 | { 22 | } 23 | 24 | private static void clearAllCachedEntries() 25 | { 26 | try 27 | { 28 | EFServiceProvider.GetCacheServiceProvider(TestCacheProvider.CacheManagerCoreRedis).ClearAllCachedEntries(); 29 | } 30 | catch (Exception ex) 31 | { 32 | Console.WriteLine(ex); 33 | } 34 | } 35 | 36 | private static void startDb() 37 | { 38 | var serviceProvider = EFServiceProvider.GetConfiguredContextServiceProvider(TestCacheProvider.BuiltInInMemory, 39 | LogLevel.Debug, cacheAllQueries: false); 40 | 41 | var serviceScope = serviceProvider.GetRequiredService(); 42 | serviceScope.Initialize(); 43 | serviceScope.SeedData(); 44 | } 45 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests/Settings/DBNullFormatter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MessagePack; 3 | using MessagePack.Formatters; 4 | 5 | namespace EFCoreSecondLevelCacheInterceptor.Tests; 6 | 7 | public class DBNullFormatter : IMessagePackFormatter 8 | { 9 | public static readonly DBNullFormatter Instance = new(); 10 | 11 | private DBNullFormatter() 12 | { 13 | } 14 | 15 | public void Serialize(ref MessagePackWriter writer, DBNull value, MessagePackSerializerOptions options) 16 | => writer.WriteNil(); 17 | 18 | public DBNull Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) => DBNull.Value; 19 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests/Settings/RandomNumberProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | 4 | namespace EFCoreSecondLevelCacheInterceptor.Tests 5 | { 6 | /// 7 | /// Provides methods for generating cryptographically-strong random numbers. 8 | /// 9 | public static class RandomNumberProvider 10 | { 11 | private static readonly RandomNumberGenerator _rand = RandomNumberGenerator.Create(); 12 | 13 | /// 14 | /// Generates a random non-negative number. 15 | /// 16 | public static int Next() 17 | { 18 | var randb = new byte[4]; 19 | _rand.GetBytes(randb); 20 | var value = BitConverter.ToInt32(randb, 0); 21 | if (value < 0) value = -value; 22 | return value; 23 | } 24 | 25 | /// 26 | /// Generates a random non-negative number less than or equal to max. 27 | /// 28 | /// The maximum possible value. 29 | public static int Next(int max) 30 | { 31 | var randb = new byte[4]; 32 | _rand.GetBytes(randb); 33 | var value = BitConverter.ToInt32(randb, 0); 34 | value = value % (max + 1); // % calculates remainder 35 | if (value < 0) value = -value; 36 | return value; 37 | } 38 | 39 | /// 40 | /// Generates a random non-negative number bigger than or equal to min and less than or 41 | /// equal to max. 42 | /// 43 | /// The minimum possible value. 44 | /// The maximum possible value. 45 | public static int Next(int min, int max) 46 | { 47 | var value = Next(max - min) + min; 48 | return value; 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests/XxHashTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | [assembly: Parallelize(Workers = 0, Scope = ExecutionScope.MethodLevel)] // Workers: The number of threads to run the tests. Set it to 0 to use the number of core of your computer. 4 | 5 | namespace EFCoreSecondLevelCacheInterceptor.Tests; 6 | 7 | [TestClass] 8 | public class XxHashTests 9 | { 10 | [TestMethod] 11 | public void TestXxHashReturnsCorrectValue() 12 | { 13 | byte[] data = 14 | { 15 | 0x60, 0x82, 0x40, 0x77, 0x8a, 0x0e, 0xe4, 0xd5, 16 | 0x85, 0x1f, 0xa6, 0x86, 0x34, 0x01, 0xd7, 0xf2, 17 | 0x30, 0x5d, 0x84, 0x54, 0x15, 0xf9, 0xbd, 0x03, 18 | 0x4b, 0x0f, 0x90, 0x4e, 0xf5, 0x57, 0x21, 0x21, 19 | 0xed, 0x8c, 0x19, 0x93, 0xbd, 0x01, 0x12, 0x0c, 20 | 0x20, 0xb0, 0x33, 0x98, 0x4b, 0xe7, 0xc1, 0x0a, 21 | 0x27, 0x6d, 0xb3, 0x5c, 0xc7, 0xc0, 0xd0, 0xa0, 22 | 0x7e, 0x28, 0xce, 0x46, 0x85, 0xb7, 0x2b, 0x16, 23 | }; 24 | var hash = new XxHash64Unsafe().ComputeHash(data); 25 | Assert.AreEqual((ulong)0x4c0a65b1ef9ea060, hash); 26 | } 27 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests/_1-dotnet_test.bat: -------------------------------------------------------------------------------- 1 | dotnet test 2 | pause -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests/_Issue165.bat: -------------------------------------------------------------------------------- 1 | dotnet test -c Release --filter "FullyQualifiedName=EFCoreSecondLevelCacheInterceptor.Tests.EFCacheDependenciesProcessorTests.TestGetCacheDependenciesWorksForBatchInserts" 2 | pause -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests/_PerformanceTest.bat: -------------------------------------------------------------------------------- 1 | dotnet test -c Release --filter "FullyQualifiedName=EFCoreSecondLevelCacheInterceptor.Tests.PerformanceTests.PerformanceTest" 2 | pause -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.Tests/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Warning", 5 | "System": "Warning", 6 | "Microsoft": "Warning", 7 | "Microsoft.Hosting.Lifetime": "Warning" 8 | } 9 | }, 10 | "AllowedHosts": "*", 11 | "ConnectionStrings": { 12 | "ApplicationDbContextConnection": "Server=(localdb)\\mssqllocaldb;Initial Catalog=EFSecondLevelCacheCore2020;AttachDBFilename=%CONTENTROOTPATH%\\App_Data\\EFSecondLevelCacheCore2020.mdf;Trusted_Connection=True;" 13 | }, 14 | "RedisConfiguration": "localhost:6379" 15 | } 16 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.UnitTests/EFCacheKeyPrefixProviderTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Options; 2 | using Moq; 3 | 4 | namespace EFCoreSecondLevelCacheInterceptor.UnitTests; 5 | 6 | // ReSharper disable once InconsistentNaming 7 | public class EFCacheKeyPrefixProviderTests 8 | { 9 | [Fact] 10 | public void Constructor_ThrowsArgumentNullException_WhenCacheSettingsIsNull() 11 | { 12 | // Arrange 13 | var serviceProvider = new Mock().Object; 14 | 15 | // ReSharper disable once ObjectCreationAsStatement 16 | void Act() => new EFCacheKeyPrefixProvider(serviceProvider, null!); 17 | 18 | // Act && Assert 19 | Assert.Throws("cacheSettings", Act); 20 | } 21 | 22 | [Fact] 23 | public void GetCacheKeyPrefix_ReturnsCacheKeyPrefixSelectorResult_WhenSelectorIsNotNull() 24 | { 25 | // Arrange 26 | var serviceProvider = new Mock().Object; 27 | var cacheSettings = Options.Create(new EFCoreSecondLevelCacheSettings 28 | { 29 | CacheKeyPrefixSelector = _ => "CustomPrefix" 30 | }); 31 | 32 | var provider = new EFCacheKeyPrefixProvider(serviceProvider, cacheSettings); 33 | 34 | // Act 35 | var actual = provider.GetCacheKeyPrefix(); 36 | 37 | // Assert 38 | Assert.Equal("CustomPrefix", actual); 39 | } 40 | 41 | [Fact] 42 | public void GetCacheKeyPrefix_ReturnsCacheKeyPrefix_WhenSelectorIsNull() 43 | { 44 | // Arrange 45 | var serviceProvider = new Mock().Object; 46 | var cacheSettings = Options.Create(new EFCoreSecondLevelCacheSettings 47 | { 48 | CacheKeyPrefix = "DefaultPrefix", 49 | CacheKeyPrefixSelector = null 50 | }); 51 | 52 | var provider = new EFCacheKeyPrefixProvider(serviceProvider, cacheSettings); 53 | 54 | // Act 55 | var actual = provider.GetCacheKeyPrefix(); 56 | 57 | // Assert 58 | Assert.Equal("DefaultPrefix", actual); 59 | } 60 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.UnitTests/EFCoreSecondLevelCacheInterceptor.UnitTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net9.0 4 | EFCoreSecondLevelCacheInterceptor.UnitTests 5 | EFCoreSecondLevelCacheInterceptor.UnitTests 6 | false 7 | false 8 | false 9 | false 10 | enable 11 | false 12 | true 13 | disable 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.UnitTests/EFTableColumnInfoTests.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor.UnitTests; 2 | 3 | // ReSharper disable once InconsistentNaming 4 | public class EFTableColumnInfoTests 5 | { 6 | [Fact] 7 | public void ToString_ReturnsFormattedString_WithValidProperties() 8 | { 9 | // Arrange 10 | var columnInfo = new EFTableColumnInfo 11 | { 12 | Ordinal = 1, 13 | Name = "ColumnName", 14 | DbTypeName = "DbType", 15 | TypeName = "Type" 16 | }; 17 | 18 | // Act 19 | var actual = columnInfo.ToString(); 20 | 21 | // Assert 22 | Assert.Equal("Ordinal: 1, Name: ColumnName, DbTypeName: DbType, TypeName= Type.", actual); 23 | } 24 | 25 | [Fact] 26 | public void ToString_ReturnsFormattedString_WithDefaultProperties() 27 | { 28 | // Arrange 29 | var columnInfo = new EFTableColumnInfo(); 30 | 31 | // Act 32 | var actual = columnInfo.ToString(); 33 | 34 | // Assert 35 | Assert.Equal("Ordinal: 0, Name: , DbTypeName: , TypeName= .", actual); 36 | } 37 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.UnitTests/EFTableRowTests.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor.UnitTests; 2 | 3 | // ReSharper disable once InconsistentNaming 4 | public class EFTableRowTests 5 | { 6 | [Fact] 7 | public void Constructor_ShouldInitializeValues() 8 | { 9 | // Arrange 10 | var values = new List { 1, "test" }; 11 | 12 | // Act 13 | var row = new EFTableRow(values); 14 | 15 | // Assert 16 | Assert.Equal(values, row.Values); 17 | } 18 | 19 | [Fact] 20 | public void GetValues_ShouldReturnExpectedValues() 21 | { 22 | // Arrange 23 | var expected = new List { 1, "test" }; 24 | var row = new EFTableRow(expected); 25 | 26 | // Act 27 | var actual = row.Values; 28 | 29 | // Assert 30 | Assert.Equal(expected, actual); 31 | } 32 | 33 | [Fact] 34 | public void GetDepth_ShouldReturnExpectedCount() 35 | { 36 | // Arrange 37 | const int expected = 1; 38 | var values = new List { 1, "test" }; 39 | var row = new EFTableRow(values) { Depth = expected }; 40 | 41 | // Act 42 | var actual = row.Depth; 43 | 44 | // Assert 45 | Assert.Equal(expected, actual); 46 | } 47 | 48 | [Fact] 49 | public void GetFieldCount_ShouldReturnExpectedCount() 50 | { 51 | // Arrange 52 | var values = new List { 1, "test" }; 53 | var row = new EFTableRow(values); 54 | 55 | // Act 56 | var fieldCount = row.FieldCount; 57 | 58 | // Assert 59 | Assert.Equal(values.Count, fieldCount); 60 | } 61 | 62 | [Fact] 63 | public void GetByIndexer_ShouldReturnExpectedValue() 64 | { 65 | // Arrange 66 | var expected = Guid.NewGuid().ToString(); 67 | var values = new List { 1, expected }; 68 | var row = new EFTableRow(values); 69 | 70 | // Act 71 | var value = row[1]; 72 | 73 | // Assert 74 | Assert.Equal(expected, value); 75 | } 76 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.UnitTests/LockProviderTests.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor.UnitTests; 2 | 3 | public class LockProviderTests 4 | { 5 | [Fact] 6 | public void Lock_ReturnsNonNullReleaser() 7 | { 8 | // Arrange 9 | var lockProvider = new LockProvider(); 10 | 11 | // Act 12 | var releaser = lockProvider.Lock(); 13 | 14 | // Assert 15 | Assert.IsAssignableFrom(releaser); 16 | } 17 | 18 | [Fact] 19 | public async Task LockAsync_ReturnsNonNullReleaser() 20 | { 21 | // Arrange 22 | var lockProvider = new LockProvider(); 23 | 24 | // Act 25 | var releaser = await lockProvider.LockAsync(); 26 | 27 | // Assert 28 | Assert.IsAssignableFrom(releaser); 29 | } 30 | 31 | [Fact] 32 | public void Lock_CanBeDisposed() 33 | { 34 | // Arrange 35 | var lockProvider = new LockProvider(); 36 | var releaser = lockProvider.Lock(); 37 | 38 | // Act 39 | releaser?.Dispose(); 40 | 41 | // Assert 42 | Assert.True(condition: true); // If no exception is thrown, the test passes 43 | } 44 | 45 | [Fact] 46 | public async Task LockAsync_CanBeDisposed() 47 | { 48 | // Arrange 49 | var lockProvider = new LockProvider(); 50 | var releaser = await lockProvider.LockAsync(); 51 | 52 | // Act 53 | releaser?.Dispose(); 54 | 55 | // Assert 56 | Assert.True(condition: true); // If no exception is thrown, the test passes 57 | } 58 | 59 | [Fact] 60 | public void Dispose_DisposesLockProvider() 61 | { 62 | // Arrange 63 | var lockProvider = new LockProvider(); 64 | 65 | // Act 66 | lockProvider.Dispose(); 67 | 68 | // Assert 69 | Assert.True(condition: true); // If no exception is thrown, the test passes 70 | } 71 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.UnitTests/MockDisposable.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor.UnitTests; 2 | 3 | public class MockDisposable : IDisposable 4 | { 5 | private bool _disposed; 6 | 7 | public void Dispose() 8 | { 9 | Dispose(disposing: true); 10 | 11 | // tell the GC not to finalize 12 | GC.SuppressFinalize(this); 13 | } 14 | 15 | protected virtual void Dispose(bool disposing) 16 | { 17 | if (!_disposed) 18 | { 19 | if (disposing) 20 | { 21 | // Not in destructor, OK to reference other objects 22 | } 23 | 24 | // perform cleanup for this object 25 | } 26 | 27 | _disposed = true; 28 | } 29 | 30 | ~MockDisposable() => Dispose(disposing: false); 31 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.UnitTests/TableEntityInfoTests.cs: -------------------------------------------------------------------------------- 1 | namespace EFCoreSecondLevelCacheInterceptor.UnitTests; 2 | 3 | public class TableEntityInfoTests 4 | { 5 | [Fact] 6 | public void ToString_ReturnsExpectedFormat_WhenClrTypeAndTableNameAreSet() 7 | { 8 | // Arrange 9 | var entityInfo = new TableEntityInfo 10 | { 11 | ClrType = typeof(string), 12 | TableName = "TestTable" 13 | }; 14 | 15 | // Act 16 | var actual = entityInfo.ToString(); 17 | 18 | // Assert 19 | Assert.Equal("System.String::TestTable", actual); 20 | } 21 | 22 | [Fact] 23 | public void ToString_ReturnsExpectedFormat_WhenClrTypeIsNull() 24 | { 25 | // Arrange 26 | var entityInfo = new TableEntityInfo 27 | { 28 | ClrType = null!, 29 | TableName = "TestTable" 30 | }; 31 | 32 | // Act 33 | var actual = entityInfo.ToString(); 34 | 35 | // Assert 36 | Assert.Equal("::TestTable", actual); 37 | } 38 | 39 | [Fact] 40 | public void ToString_ReturnsExpectedFormat_WhenTableNameIsNull() 41 | { 42 | // Arrange 43 | var entityInfo = new TableEntityInfo 44 | { 45 | ClrType = typeof(string), 46 | TableName = null! 47 | }; 48 | 49 | // Act 50 | var actual = entityInfo.ToString(); 51 | 52 | // Assert 53 | Assert.Equal("System.String::", actual); 54 | } 55 | 56 | [Fact] 57 | public void ToString_ReturnsExpectedFormat_WhenBothClrTypeAndTableNameAreNull() 58 | { 59 | // Arrange 60 | var entityInfo = new TableEntityInfo 61 | { 62 | ClrType = null!, 63 | TableName = null! 64 | }; 65 | 66 | // Act 67 | var actual = entityInfo.ToString(); 68 | 69 | // Assert 70 | Assert.Equal("::", actual); 71 | } 72 | } -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.UnitTests/_run_tests.cmd: -------------------------------------------------------------------------------- 1 | dotnet test --logger "console;verbosity=detailed" 2 | pause -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.WorkerServiceWithLamar/App_Data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/EFCoreSecondLevelCacheInterceptor.WorkerServiceWithLamar/App_Data/.gitkeep -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.WorkerServiceWithLamar/EFCoreSecondLevelCacheInterceptor.WorkerServiceWithLamar.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net9.0 4 | dotnet-EFCoreSecondLevelCacheInterceptor.WorkerServiceWithLamar-7BDED8C3-74B4-4CA0-82AA-E5452A3AF4A7 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.WorkerServiceWithLamar/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "EFCoreSecondLevelCacheInterceptor.WorkerServiceWithLamar": { 4 | "commandName": "Project", 5 | "environmentVariables": { 6 | "DOTNET_ENVIRONMENT": "Development" 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.WorkerServiceWithLamar/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.WorkerServiceWithLamar/_1-dotnet_run.bat: -------------------------------------------------------------------------------- 1 | dotnet watch run -------------------------------------------------------------------------------- /src/Tests/EFCoreSecondLevelCacheInterceptor.WorkerServiceWithLamar/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Debug", 6 | "Microsoft": "Debug", 7 | "Microsoft.Hosting.Lifetime": "Debug" 8 | } 9 | }, 10 | "ConnectionStrings": { 11 | "ApplicationDbContextConnection": "Server=(localdb)\\mssqllocaldb;Initial Catalog=EFSecondLevelCacheCore20203;AttachDBFilename=%CONTENTROOTPATH%\\App_Data\\EFSecondLevelCacheCore20203.mdf;Trusted_Connection=True;" 12 | }, 13 | "RedisConfiguration": "localhost:6379" 14 | } 15 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/App_Data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/Issues/Issue123WithMessagePack/App_Data/.gitkeep -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/DataLayer/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | using Issue123WithMessagePack.Entities; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace Issue123WithMessagePack.DataLayer 5 | { 6 | public class ApplicationDbContext : DbContext 7 | { 8 | public ApplicationDbContext(DbContextOptions options) 9 | : base(options) 10 | { 11 | } 12 | 13 | public DbSet People { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/DataLayer/MsSqlContextFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Design; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Configuration; 4 | using System; 5 | using System.IO; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace Issue123WithMessagePack.DataLayer 9 | { 10 | public class MsSqlContextFactory : IDesignTimeDbContextFactory 11 | { 12 | public ApplicationDbContext CreateDbContext(string[] args) 13 | { 14 | var services = new ServiceCollection(); 15 | 16 | var basePath = Directory.GetCurrentDirectory(); 17 | Console.WriteLine($"Using `{basePath}` as the ContentRootPath"); 18 | var configuration = new ConfigurationBuilder() 19 | .SetBasePath(basePath) 20 | .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) 21 | .Build(); 22 | services.AddSingleton(_ => configuration); 23 | 24 | var optionsBuilder = new DbContextOptionsBuilder(); 25 | optionsBuilder.UseSqlServer(EFServiceProvider.GetConnectionString(basePath, configuration)); 26 | return new ApplicationDbContext(optionsBuilder.Options); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/Entities/Person.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Issue123WithMessagePack.Entities; 4 | 5 | public class Person 6 | { 7 | public int Id { get; set; } 8 | 9 | public string Name { get; set; } 10 | 11 | public DateTime Date { get; set; } 12 | 13 | public DateTimeOffset DateOffset { get; set; } 14 | 15 | public TimeSpan Span { get; set; } 16 | 17 | public DateOnly DateOnly { get; set; } 18 | 19 | public TimeOnly TimeOnly { get; set; } 20 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/Issue123WithMessagePack.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net9.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | all 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/Migrations/20210509052521_V2021_05_09_0954.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using Issue123WithMessagePack.DataLayer; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | 9 | namespace Issue123WithMessagePack.Migrations 10 | { 11 | [DbContext(typeof(ApplicationDbContext))] 12 | [Migration("20210509052521_V2021_05_09_0954")] 13 | partial class V2021_05_09_0954 14 | { 15 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 16 | { 17 | #pragma warning disable 612, 618 18 | modelBuilder 19 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 20 | .HasAnnotation("ProductVersion", "5.0.5") 21 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 22 | 23 | modelBuilder.Entity("Issue123WithMessagePack.Entities.Person", b => 24 | { 25 | b.Property("Id") 26 | .ValueGeneratedOnAdd() 27 | .HasColumnType("int") 28 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 29 | 30 | b.Property("Name") 31 | .HasColumnType("nvarchar(max)"); 32 | 33 | b.HasKey("Id"); 34 | 35 | b.ToTable("People"); 36 | }); 37 | #pragma warning restore 612, 618 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/Migrations/20210509052521_V2021_05_09_0954.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace Issue123WithMessagePack.Migrations 4 | { 5 | public partial class V2021_05_09_0954 : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.CreateTable( 10 | name: "People", 11 | columns: table => new 12 | { 13 | Id = table.Column(type: "int", nullable: false) 14 | .Annotation("SqlServer:Identity", "1, 1"), 15 | Name = table.Column(type: "nvarchar(max)", nullable: true) 16 | }, 17 | constraints: table => 18 | { 19 | table.PrimaryKey("PK_People", x => x.Id); 20 | }); 21 | } 22 | 23 | protected override void Down(MigrationBuilder migrationBuilder) 24 | { 25 | migrationBuilder.DropTable( 26 | name: "People"); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/Migrations/20220803082805_V2022_08_03_1257.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Issue123WithMessagePack.DataLayer; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Metadata; 7 | using Microsoft.EntityFrameworkCore.Migrations; 8 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 9 | 10 | #nullable disable 11 | 12 | namespace Issue123WithMessagePack.Migrations 13 | { 14 | [DbContext(typeof(ApplicationDbContext))] 15 | [Migration("20220803082805_V2022_08_03_1257")] 16 | partial class V2022_08_03_1257 17 | { 18 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 19 | { 20 | #pragma warning disable 612, 618 21 | modelBuilder 22 | .HasAnnotation("ProductVersion", "6.0.7") 23 | .HasAnnotation("Relational:MaxIdentifierLength", 128); 24 | 25 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); 26 | 27 | modelBuilder.Entity("Issue123WithMessagePack.Entities.Person", b => 28 | { 29 | b.Property("Id") 30 | .ValueGeneratedOnAdd() 31 | .HasColumnType("int"); 32 | 33 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); 34 | 35 | b.Property("Date") 36 | .HasColumnType("datetime2"); 37 | 38 | b.Property("DateOffset") 39 | .HasColumnType("datetimeoffset"); 40 | 41 | b.Property("Name") 42 | .HasColumnType("nvarchar(max)"); 43 | 44 | b.HasKey("Id"); 45 | 46 | b.ToTable("People"); 47 | }); 48 | #pragma warning restore 612, 618 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/Migrations/20220803082805_V2022_08_03_1257.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | #nullable disable 5 | 6 | namespace Issue123WithMessagePack.Migrations 7 | { 8 | public partial class V2022_08_03_1257 : Migration 9 | { 10 | protected override void Up(MigrationBuilder migrationBuilder) 11 | { 12 | migrationBuilder.AddColumn( 13 | name: "Date", 14 | table: "People", 15 | type: "datetime2", 16 | nullable: false, 17 | defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); 18 | 19 | migrationBuilder.AddColumn( 20 | name: "DateOffset", 21 | table: "People", 22 | type: "datetimeoffset", 23 | nullable: false, 24 | defaultValue: new DateTimeOffset(new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0))); 25 | } 26 | 27 | protected override void Down(MigrationBuilder migrationBuilder) 28 | { 29 | migrationBuilder.DropColumn( 30 | name: "Date", 31 | table: "People"); 32 | 33 | migrationBuilder.DropColumn( 34 | name: "DateOffset", 35 | table: "People"); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/Migrations/20230222181834_V2023_02_22_2147.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Issue123WithMessagePack.DataLayer; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Metadata; 7 | using Microsoft.EntityFrameworkCore.Migrations; 8 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 9 | 10 | #nullable disable 11 | 12 | namespace Issue123WithMessagePack.Migrations 13 | { 14 | [DbContext(typeof(ApplicationDbContext))] 15 | [Migration("20230222181834_V2023_02_22_2147")] 16 | partial class V202302222147 17 | { 18 | /// 19 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 20 | { 21 | #pragma warning disable 612, 618 22 | modelBuilder 23 | .HasAnnotation("ProductVersion", "7.0.0") 24 | .HasAnnotation("Relational:MaxIdentifierLength", 128); 25 | 26 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); 27 | 28 | modelBuilder.Entity("Issue123WithMessagePack.Entities.Person", b => 29 | { 30 | b.Property("Id") 31 | .ValueGeneratedOnAdd() 32 | .HasColumnType("int"); 33 | 34 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); 35 | 36 | b.Property("Date") 37 | .HasColumnType("datetime2"); 38 | 39 | b.Property("DateOffset") 40 | .HasColumnType("datetimeoffset"); 41 | 42 | b.Property("Name") 43 | .HasColumnType("nvarchar(max)"); 44 | 45 | b.Property("Span") 46 | .HasColumnType("time"); 47 | 48 | b.HasKey("Id"); 49 | 50 | b.ToTable("People"); 51 | }); 52 | #pragma warning restore 612, 618 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/Migrations/20230222181834_V2023_02_22_2147.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | #nullable disable 5 | 6 | namespace Issue123WithMessagePack.Migrations 7 | { 8 | /// 9 | public partial class V202302222147 : Migration 10 | { 11 | /// 12 | protected override void Up(MigrationBuilder migrationBuilder) 13 | { 14 | migrationBuilder.AddColumn( 15 | name: "Span", 16 | table: "People", 17 | type: "time", 18 | nullable: false, 19 | defaultValue: new TimeSpan(0, 0, 0, 0, 0)); 20 | } 21 | 22 | /// 23 | protected override void Down(MigrationBuilder migrationBuilder) 24 | { 25 | migrationBuilder.DropColumn( 26 | name: "Span", 27 | table: "People"); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/Migrations/20230225090316_V2023_02_25_1232.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Issue123WithMessagePack.DataLayer; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Metadata; 7 | using Microsoft.EntityFrameworkCore.Migrations; 8 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 9 | 10 | #nullable disable 11 | 12 | namespace Issue123WithMessagePack.Migrations 13 | { 14 | [DbContext(typeof(ApplicationDbContext))] 15 | [Migration("20230225090316_V2023_02_25_1232")] 16 | partial class V2023_02_25_1232 17 | { 18 | /// 19 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 20 | { 21 | #pragma warning disable 612, 618 22 | modelBuilder 23 | .HasAnnotation("ProductVersion", "8.0.0-preview.1.23111.4") 24 | .HasAnnotation("Relational:MaxIdentifierLength", 128); 25 | 26 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); 27 | 28 | modelBuilder.Entity("Issue123WithMessagePack.Entities.Person", b => 29 | { 30 | b.Property("Id") 31 | .ValueGeneratedOnAdd() 32 | .HasColumnType("int"); 33 | 34 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); 35 | 36 | b.Property("Date") 37 | .HasColumnType("datetime2"); 38 | 39 | b.Property("DateOffset") 40 | .HasColumnType("datetimeoffset"); 41 | 42 | b.Property("DateOnly") 43 | .HasColumnType("date"); 44 | 45 | b.Property("Name") 46 | .HasColumnType("nvarchar(max)"); 47 | 48 | b.Property("Span") 49 | .HasColumnType("time"); 50 | 51 | b.Property("TimeOnly") 52 | .HasColumnType("time"); 53 | 54 | b.HasKey("Id"); 55 | 56 | b.ToTable("People"); 57 | }); 58 | #pragma warning restore 612, 618 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/Migrations/20230225090316_V2023_02_25_1232.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | #nullable disable 5 | 6 | namespace Issue123WithMessagePack.Migrations 7 | { 8 | /// 9 | public partial class V2023_02_25_1232 : Migration 10 | { 11 | /// 12 | protected override void Up(MigrationBuilder migrationBuilder) 13 | { 14 | migrationBuilder.AddColumn( 15 | name: "DateOnly", 16 | table: "People", 17 | type: "date", 18 | nullable: false, 19 | defaultValue: new DateOnly(1, 1, 1)); 20 | 21 | migrationBuilder.AddColumn( 22 | name: "TimeOnly", 23 | table: "People", 24 | type: "time", 25 | nullable: false, 26 | defaultValue: new TimeOnly(0, 0, 0)); 27 | } 28 | 29 | /// 30 | protected override void Down(MigrationBuilder migrationBuilder) 31 | { 32 | migrationBuilder.DropColumn( 33 | name: "DateOnly", 34 | table: "People"); 35 | 36 | migrationBuilder.DropColumn( 37 | name: "TimeOnly", 38 | table: "People"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/Migrations/ApplicationDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Issue123WithMessagePack.DataLayer; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Metadata; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | 9 | #nullable disable 10 | 11 | namespace Issue123WithMessagePack.Migrations 12 | { 13 | [DbContext(typeof(ApplicationDbContext))] 14 | partial class ApplicationDbContextModelSnapshot : ModelSnapshot 15 | { 16 | protected override void BuildModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .HasAnnotation("ProductVersion", "8.0.0-preview.1.23111.4") 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128); 22 | 23 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); 24 | 25 | modelBuilder.Entity("Issue123WithMessagePack.Entities.Person", b => 26 | { 27 | b.Property("Id") 28 | .ValueGeneratedOnAdd() 29 | .HasColumnType("int"); 30 | 31 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); 32 | 33 | b.Property("Date") 34 | .HasColumnType("datetime2"); 35 | 36 | b.Property("DateOffset") 37 | .HasColumnType("datetimeoffset"); 38 | 39 | b.Property("DateOnly") 40 | .HasColumnType("date"); 41 | 42 | b.Property("Name") 43 | .HasColumnType("nvarchar(max)"); 44 | 45 | b.Property("Span") 46 | .HasColumnType("time"); 47 | 48 | b.Property("TimeOnly") 49 | .HasColumnType("time"); 50 | 51 | b.HasKey("Id"); 52 | 53 | b.ToTable("People"); 54 | }); 55 | #pragma warning restore 612, 618 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/_01-add_migrations.cmd: -------------------------------------------------------------------------------- 1 | For /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c_%%a_%%b) 2 | For /f "tokens=1-2 delims=/:" %%a in ("%TIME: =0%") do (set mytime=%%a%%b) 3 | dotnet tool update --global dotnet-ef --version 8.0.0-preview.1.23111.4 4 | dotnet build 5 | dotnet ef migrations add V%mydate%_%mytime% --context ApplicationDbContext 6 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/_02-dotnet_run.bat: -------------------------------------------------------------------------------- 1 | dotnet watch run -------------------------------------------------------------------------------- /src/Tests/Issues/Issue123WithMessagePack/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Debug", 6 | "Microsoft": "Debug", 7 | "Microsoft.Hosting.Lifetime": "Debug" 8 | } 9 | }, 10 | "AllowedHosts": "*", 11 | "ConnectionStrings": { 12 | "ApplicationDbContextConnection": "Server=(localdb)\\mssqllocaldb;Initial Catalog=Issue123WithMessagePack;AttachDBFilename=%CONTENTROOTPATH%\\App_Data\\Issue123WithMessagePack.mdf;Trusted_Connection=True;" 13 | }, 14 | "RedisConfiguration": "localhost:6379" 15 | } 16 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue125EF5x/App_Data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/Issues/Issue125EF5x/App_Data/.gitkeep -------------------------------------------------------------------------------- /src/Tests/Issues/Issue125EF5x/DataLayer/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | using Issue125EF5x.Entities; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace Issue125EF5x.DataLayer 5 | { 6 | public class ApplicationDbContext : DbContext 7 | { 8 | public ApplicationDbContext(DbContextOptions options) 9 | : base(options) 10 | { 11 | } 12 | 13 | public DbSet People { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue125EF5x/DataLayer/MsSqlContextFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Design; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Configuration; 4 | using System; 5 | using System.IO; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace Issue125EF5x.DataLayer 9 | { 10 | public class MsSqlContextFactory : IDesignTimeDbContextFactory 11 | { 12 | public ApplicationDbContext CreateDbContext(string[] args) 13 | { 14 | var services = new ServiceCollection(); 15 | 16 | var basePath = Directory.GetCurrentDirectory(); 17 | Console.WriteLine($"Using `{basePath}` as the ContentRootPath"); 18 | var configuration = new ConfigurationBuilder() 19 | .SetBasePath(basePath) 20 | .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) 21 | .Build(); 22 | services.AddSingleton(_ => configuration); 23 | 24 | var optionsBuilder = new DbContextOptionsBuilder(); 25 | optionsBuilder.UseSqlServer(EFServiceProvider.GetConnectionString(basePath, configuration)); 26 | return new ApplicationDbContext(optionsBuilder.Options); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue125EF5x/Entities/Person.cs: -------------------------------------------------------------------------------- 1 | namespace Issue125EF5x.Entities 2 | { 3 | public class Person 4 | { 5 | public int Id { get; set; } 6 | 7 | public string Name { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue125EF5x/Issue125EF5x.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net9.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | all 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue125EF5x/Migrations/20210509052521_V2021_05_09_0954.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using Issue125EF5x.DataLayer; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | 9 | namespace Issue125EF5x.Migrations 10 | { 11 | [DbContext(typeof(ApplicationDbContext))] 12 | [Migration("20210509052521_V2021_05_09_0954")] 13 | partial class V2021_05_09_0954 14 | { 15 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 16 | { 17 | #pragma warning disable 612, 618 18 | modelBuilder 19 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 20 | .HasAnnotation("ProductVersion", "5.0.5") 21 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 22 | 23 | modelBuilder.Entity("Issue125EF5x.Entities.Person", b => 24 | { 25 | b.Property("Id") 26 | .ValueGeneratedOnAdd() 27 | .HasColumnType("int") 28 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 29 | 30 | b.Property("Name") 31 | .HasColumnType("nvarchar(max)"); 32 | 33 | b.HasKey("Id"); 34 | 35 | b.ToTable("People"); 36 | }); 37 | #pragma warning restore 612, 618 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue125EF5x/Migrations/20210509052521_V2021_05_09_0954.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace Issue125EF5x.Migrations 4 | { 5 | public partial class V2021_05_09_0954 : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.CreateTable( 10 | name: "People", 11 | columns: table => new 12 | { 13 | Id = table.Column(type: "int", nullable: false) 14 | .Annotation("SqlServer:Identity", "1, 1"), 15 | Name = table.Column(type: "nvarchar(max)", nullable: true) 16 | }, 17 | constraints: table => 18 | { 19 | table.PrimaryKey("PK_People", x => x.Id); 20 | }); 21 | } 22 | 23 | protected override void Down(MigrationBuilder migrationBuilder) 24 | { 25 | migrationBuilder.DropTable( 26 | name: "People"); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue125EF5x/Migrations/ApplicationDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using Issue125EF5x.DataLayer; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 7 | 8 | namespace Issue125EF5x.Migrations 9 | { 10 | [DbContext(typeof(ApplicationDbContext))] 11 | partial class ApplicationDbContextModelSnapshot : ModelSnapshot 12 | { 13 | protected override void BuildModel(ModelBuilder modelBuilder) 14 | { 15 | #pragma warning disable 612, 618 16 | modelBuilder 17 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 18 | .HasAnnotation("ProductVersion", "5.0.5") 19 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 20 | 21 | modelBuilder.Entity("Issue125EF5x.Entities.Person", b => 22 | { 23 | b.Property("Id") 24 | .ValueGeneratedOnAdd() 25 | .HasColumnType("int") 26 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 27 | 28 | b.Property("Name") 29 | .HasColumnType("nvarchar(max)"); 30 | 31 | b.HasKey("Id"); 32 | 33 | b.ToTable("People"); 34 | }); 35 | #pragma warning restore 612, 618 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue125EF5x/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.EntityFrameworkCore; 3 | using System; 4 | using Issue125EF5x.Entities; 5 | using EFCoreSecondLevelCacheInterceptor; 6 | 7 | namespace Issue125EF5x 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | initDb(); 14 | 15 | EFServiceProvider.GetRequiredService().ClearAllCachedEntries(); 16 | 17 | EFServiceProvider.RunInContext(context => 18 | { 19 | var cachedPeople = context.People.ToList(); 20 | cachedPeople = context.People.ToList(); 21 | foreach (var person in cachedPeople) 22 | { 23 | Console.WriteLine($"{person.Id}, {person.Name}"); 24 | } 25 | 26 | var person1 = context.People.Single(x => x.Id == 1); 27 | person1 = context.People.Single(x => x.Id == 1); 28 | Console.WriteLine($"{person1.Id}, {person1.Name}"); 29 | }); 30 | } 31 | 32 | private static void initDb() 33 | { 34 | EFServiceProvider.RunInContext(context => 35 | { 36 | context.Database.Migrate(); 37 | 38 | if (!context.People.Any()) 39 | { 40 | context.People.Add(new Person 41 | { 42 | Name = "Bill", 43 | }); 44 | context.SaveChanges(); 45 | } 46 | }); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue125EF5x/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue125EF5x/_01-add_migrations.cmd: -------------------------------------------------------------------------------- 1 | For /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c_%%a_%%b) 2 | For /f "tokens=1-2 delims=/:" %%a in ("%TIME: =0%") do (set mytime=%%a%%b) 3 | dotnet tool update --global dotnet-ef --version 6.0.7 4 | dotnet build 5 | dotnet ef migrations add V%mydate%_%mytime% --context ApplicationDbContext 6 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue125EF5x/_02-dotnet_run.bat: -------------------------------------------------------------------------------- 1 | dotnet watch run -------------------------------------------------------------------------------- /src/Tests/Issues/Issue125EF5x/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Debug", 6 | "Microsoft": "Debug", 7 | "Microsoft.Hosting.Lifetime": "Debug" 8 | } 9 | }, 10 | "AllowedHosts": "*", 11 | "ConnectionStrings": { 12 | "ApplicationDbContextConnection": "Server=(localdb)\\mssqllocaldb;Initial Catalog=Issue125EF5x;AttachDBFilename=%CONTENTROOTPATH%\\App_Data\\Issue125EF5x.mdf;Trusted_Connection=True;" 13 | }, 14 | "RedisConfiguration": "localhost:6379" 15 | } 16 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue12MySQL/DataLayer/MySQLContextFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Design; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Configuration; 4 | using System; 5 | using System.IO; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace Issue12MySQL.DataLayer 9 | { 10 | public class MySQLContextFactory : IDesignTimeDbContextFactory 11 | { 12 | public ApplicationDbContext CreateDbContext(string[] args) 13 | { 14 | var services = new ServiceCollection(); 15 | 16 | var basePath = Directory.GetCurrentDirectory(); 17 | Console.WriteLine($"Using `{basePath}` as the ContentRootPath"); 18 | var configuration = new ConfigurationBuilder() 19 | .SetBasePath(basePath) 20 | .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) 21 | .Build(); 22 | services.AddSingleton(_ => configuration); 23 | 24 | var optionsBuilder = new DbContextOptionsBuilder(); 25 | optionsBuilder.UseMySQL(configuration["ConnectionStrings:ApplicationDbContextConnection"]); 26 | return new ApplicationDbContext(optionsBuilder.Options); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue12MySQL/Entities/Person.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace Issue12MySQL.Entities 5 | { 6 | public class Person 7 | { 8 | public int Id { get; set; } 9 | 10 | public string Name { get; set; } 11 | 12 | public DateTime AddDate { get; set; } 13 | 14 | public DateTime? UpdateDate { get; set; } 15 | 16 | public long Points { get; set; } 17 | 18 | public bool IsActive { get; set; } 19 | 20 | public byte ByteValue { get; set; } 21 | 22 | public char CharValue { get; set; } 23 | 24 | public DateTimeOffset DateTimeOffsetValue { get; set; } 25 | 26 | public decimal DecimalValue { get; set; } 27 | 28 | public double DoubleValue { set; get; } 29 | 30 | public float FloatValue { set; get; } 31 | 32 | public Guid GuidValue { set; get; } 33 | 34 | public TimeSpan TimeSpanValue { set; get; } 35 | 36 | public short ShortValue { set; get; } 37 | 38 | public byte[] ByteArrayValue { get; set; } 39 | 40 | public uint UintValue { set; get; } 41 | 42 | public ulong UlongValue { set; get; } 43 | 44 | public ulong UshortValue { set; get; } 45 | } 46 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue12MySQL/Issue12MySQL.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net9.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | all 19 | 20 | 21 | 22 | 23 | 24 | runtime; build; native; contentfiles; analyzers; buildtransitive 25 | all 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue12MySQL/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue12MySQL/_01-add_migrations.cmd: -------------------------------------------------------------------------------- 1 | For /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c_%%a_%%b) 2 | For /f "tokens=1-2 delims=/:" %%a in ("%TIME: =0%") do (set mytime=%%a%%b) 3 | dotnet tool update --global dotnet-ef --version 6.0.7 4 | dotnet build 5 | dotnet ef migrations add V%mydate%_%mytime% --context ApplicationDbContext 6 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue12MySQL/_02-dotnet_run.bat: -------------------------------------------------------------------------------- 1 | dotnet watch run -------------------------------------------------------------------------------- /src/Tests/Issues/Issue12MySQL/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Debug", 6 | "Microsoft": "Debug", 7 | "Microsoft.Hosting.Lifetime": "Debug" 8 | } 9 | }, 10 | "AllowedHosts": "*", 11 | "ConnectionStrings": { 12 | "ApplicationDbContextConnection": "server=localhost;port=3306;user=root;password=MySql-1399#1;database=Issue137MySQL;TreatTinyAsBoolean=true;AllowZeroDateTime=true;ConvertZeroDateTime=true;" 13 | }, 14 | "RedisConfiguration": "localhost:6379" 15 | } 16 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue12PostgreSql/DataLayer/NpgSqlContextFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Design; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Configuration; 4 | using System; 5 | using System.IO; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace Issue12PostgreSql.DataLayer 9 | { 10 | public class NpgSqlContextFactory : IDesignTimeDbContextFactory 11 | { 12 | public ApplicationDbContext CreateDbContext(string[] args) 13 | { 14 | var services = new ServiceCollection(); 15 | 16 | var basePath = Directory.GetCurrentDirectory(); 17 | Console.WriteLine($"Using `{basePath}` as the ContentRootPath"); 18 | var configuration = new ConfigurationBuilder() 19 | .SetBasePath(basePath) 20 | .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) 21 | .Build(); 22 | services.AddSingleton(_ => configuration); 23 | 24 | var optionsBuilder = new DbContextOptionsBuilder(); 25 | optionsBuilder.UseNpgsql(configuration["ConnectionStrings:ApplicationDbContextConnection"]); 26 | return new ApplicationDbContext(optionsBuilder.Options); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue12PostgreSql/Issue12PostgreSql.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net9.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | all 19 | 20 | 21 | 22 | 23 | runtime; build; native; contentfiles; analyzers; buildtransitive 24 | all 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue12PostgreSql/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue12PostgreSql/_01-add_migrations.cmd: -------------------------------------------------------------------------------- 1 | For /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c_%%a_%%b) 2 | For /f "tokens=1-2 delims=/:" %%a in ("%TIME: =0%") do (set mytime=%%a%%b) 3 | dotnet tool update --global dotnet-ef --version 6.0.7 4 | dotnet build 5 | dotnet ef migrations add V%mydate%_%mytime% --context ApplicationDbContext 6 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue12PostgreSql/_02-dotnet_run.bat: -------------------------------------------------------------------------------- 1 | dotnet watch run -------------------------------------------------------------------------------- /src/Tests/Issues/Issue12PostgreSql/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Debug", 6 | "Microsoft": "Debug", 7 | "Microsoft.Hosting.Lifetime": "Debug" 8 | } 9 | }, 10 | "AllowedHosts": "*", 11 | "ConnectionStrings": { 12 | "ApplicationDbContextConnection": "User ID=Vahid;Password=NpgSql-1399#1;Host=localhost;Port=5432;Database=Issue12PostgreSql;Pooling=true;" 13 | }, 14 | "RedisConfiguration": "localhost:6379" 15 | } 16 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue154/App_Data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/Issues/Issue154/App_Data/.gitkeep -------------------------------------------------------------------------------- /src/Tests/Issues/Issue154/DataLayer/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Issue154.Entities; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 6 | using Microsoft.Extensions.Logging; 7 | 8 | namespace Issue154.DataLayer 9 | { 10 | public class ApplicationDbContext : DbContext 11 | { 12 | public ApplicationDbContext(DbContextOptions options) 13 | : base(options) 14 | { 15 | } 16 | 17 | public DbSet People { get; set; } 18 | 19 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 20 | => optionsBuilder.LogTo(message => Console.WriteLine(message)); 21 | } 22 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue154/DataLayer/SqliteContextFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Design; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Configuration; 4 | using System; 5 | using System.IO; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace Issue154.DataLayer 9 | { 10 | public class SqliteContextFactory : IDesignTimeDbContextFactory 11 | { 12 | public ApplicationDbContext CreateDbContext(string[] args) 13 | { 14 | var services = new ServiceCollection(); 15 | 16 | var basePath = Directory.GetCurrentDirectory(); 17 | Console.WriteLine($"Using `{basePath}` as the ContentRootPath"); 18 | var configuration = new ConfigurationBuilder() 19 | .SetBasePath(basePath) 20 | .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) 21 | .Build(); 22 | services.AddSingleton(_ => configuration); 23 | 24 | var optionsBuilder = new DbContextOptionsBuilder(); 25 | optionsBuilder.UseSqlite(EFServiceProvider.GetConnectionString(basePath, configuration)); 26 | return new ApplicationDbContext(optionsBuilder.Options); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue154/Entities/Person.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace Issue154.Entities 5 | { 6 | public class Person 7 | { 8 | public int Id { get; set; } 9 | 10 | public string Name { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue154/Issue154.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net9.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue154/Migrations/20220318153843_V2022_03_18_1908.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using Issue154.DataLayer; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Migrations; 6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 7 | 8 | #nullable disable 9 | 10 | namespace Issue154.Migrations 11 | { 12 | [DbContext(typeof(ApplicationDbContext))] 13 | [Migration("20220318153843_V2022_03_18_1908")] 14 | partial class V2022_03_18_1908 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder.HasAnnotation("ProductVersion", "6.0.1"); 20 | 21 | modelBuilder.Entity("Issue154.Entities.Person", b => 22 | { 23 | b.Property("Id") 24 | .ValueGeneratedOnAdd() 25 | .HasColumnType("INTEGER"); 26 | 27 | b.Property("Name") 28 | .HasColumnType("TEXT"); 29 | 30 | b.HasKey("Id"); 31 | 32 | b.ToTable("People"); 33 | }); 34 | #pragma warning restore 612, 618 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue154/Migrations/20220318153843_V2022_03_18_1908.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace Issue154.Migrations 6 | { 7 | public partial class V2022_03_18_1908 : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.CreateTable( 12 | name: "People", 13 | columns: table => new 14 | { 15 | Id = table.Column(type: "INTEGER", nullable: false) 16 | .Annotation("Sqlite:Autoincrement", true), 17 | Name = table.Column(type: "TEXT", nullable: true) 18 | }, 19 | constraints: table => 20 | { 21 | table.PrimaryKey("PK_People", x => x.Id); 22 | }); 23 | } 24 | 25 | protected override void Down(MigrationBuilder migrationBuilder) 26 | { 27 | migrationBuilder.DropTable( 28 | name: "People"); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue154/Migrations/ApplicationDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using Issue154.DataLayer; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 6 | 7 | #nullable disable 8 | 9 | namespace Issue154.Migrations 10 | { 11 | [DbContext(typeof(ApplicationDbContext))] 12 | partial class ApplicationDbContextModelSnapshot : ModelSnapshot 13 | { 14 | protected override void BuildModel(ModelBuilder modelBuilder) 15 | { 16 | #pragma warning disable 612, 618 17 | modelBuilder.HasAnnotation("ProductVersion", "6.0.1"); 18 | 19 | modelBuilder.Entity("Issue154.Entities.Person", b => 20 | { 21 | b.Property("Id") 22 | .ValueGeneratedOnAdd() 23 | .HasColumnType("INTEGER"); 24 | 25 | b.Property("Name") 26 | .HasColumnType("TEXT"); 27 | 28 | b.HasKey("Id"); 29 | 30 | b.ToTable("People"); 31 | }); 32 | #pragma warning restore 612, 618 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue154/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue154/_01-add_migrations.cmd: -------------------------------------------------------------------------------- 1 | For /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c_%%a_%%b) 2 | For /f "tokens=1-2 delims=/:" %%a in ("%TIME: =0%") do (set mytime=%%a%%b) 3 | dotnet tool update --global dotnet-ef --version 6.0.7 4 | dotnet build 5 | dotnet ef migrations add V%mydate%_%mytime% --context ApplicationDbContext 6 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue154/_02-dotnet_run.bat: -------------------------------------------------------------------------------- 1 | dotnet run 2 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue154/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Debug", 6 | "Microsoft": "Debug", 7 | "Microsoft.Hosting.Lifetime": "Debug" 8 | } 9 | }, 10 | "AllowedHosts": "*", 11 | "ConnectionStrings": { 12 | "ApplicationDbContextConnection": "Data Source=%CONTENTROOTPATH%\\App_Data\\TestDb.sqlite" 13 | }, 14 | "RedisConfiguration": "localhost:6379" 15 | } 16 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue192/App_Data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/Issues/Issue192/App_Data/.gitkeep -------------------------------------------------------------------------------- /src/Tests/Issues/Issue192/DataLayer/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | using Issue192.Entities; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace Issue192.DataLayer; 5 | 6 | public class ApplicationDbContext : DbContext 7 | { 8 | public ApplicationDbContext(DbContextOptions options) 9 | : base(options) 10 | { 11 | } 12 | 13 | public DbSet People { get; set; } 14 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue192/DataLayer/MsSqlContextFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Design; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace Issue192.DataLayer; 9 | 10 | public class MsSqlContextFactory : IDesignTimeDbContextFactory 11 | { 12 | public ApplicationDbContext CreateDbContext(string[] args) 13 | { 14 | var services = new ServiceCollection(); 15 | 16 | var basePath = Directory.GetCurrentDirectory(); 17 | Console.WriteLine($"Using `{basePath}` as the ContentRootPath"); 18 | var configuration = new ConfigurationBuilder() 19 | .SetBasePath(basePath) 20 | .AddJsonFile("appsettings.json", false, true) 21 | .Build(); 22 | services.AddSingleton(_ => configuration); 23 | 24 | var optionsBuilder = new DbContextOptionsBuilder(); 25 | optionsBuilder.UseSqlServer(EFServiceProvider.GetConnectionString(basePath, configuration)); 26 | return new ApplicationDbContext(optionsBuilder.Options); 27 | } 28 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue192/Entities/Person.cs: -------------------------------------------------------------------------------- 1 | namespace Issue192.Entities; 2 | 3 | public class Person 4 | { 5 | public int Id { get; set; } 6 | 7 | public string Name { get; set; } 8 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue192/Issue192.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net9.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | all 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue192/Migrations/20230110072026_V2023_01_10_1050.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using Issue192.DataLayer; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | 9 | #nullable disable 10 | 11 | namespace Issue192.Migrations 12 | { 13 | [DbContext(typeof(ApplicationDbContext))] 14 | [Migration("20230110072026_V2023_01_10_1050")] 15 | partial class V2023_01_10_1050 16 | { 17 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 18 | { 19 | #pragma warning disable 612, 618 20 | modelBuilder 21 | .HasAnnotation("ProductVersion", "6.0.11") 22 | .HasAnnotation("Relational:MaxIdentifierLength", 128); 23 | 24 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); 25 | 26 | modelBuilder.Entity("Issue192.Entities.Person", b => 27 | { 28 | b.Property("Id") 29 | .ValueGeneratedOnAdd() 30 | .HasColumnType("int"); 31 | 32 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); 33 | 34 | b.Property("Name") 35 | .HasColumnType("nvarchar(max)"); 36 | 37 | b.HasKey("Id"); 38 | 39 | b.ToTable("People"); 40 | }); 41 | #pragma warning restore 612, 618 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue192/Migrations/20230110072026_V2023_01_10_1050.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace Issue192.Migrations 6 | { 7 | public partial class V2023_01_10_1050 : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.CreateTable( 12 | name: "People", 13 | columns: table => new 14 | { 15 | Id = table.Column(type: "int", nullable: false) 16 | .Annotation("SqlServer:Identity", "1, 1"), 17 | Name = table.Column(type: "nvarchar(max)", nullable: true) 18 | }, 19 | constraints: table => 20 | { 21 | table.PrimaryKey("PK_People", x => x.Id); 22 | }); 23 | } 24 | 25 | protected override void Down(MigrationBuilder migrationBuilder) 26 | { 27 | migrationBuilder.DropTable( 28 | name: "People"); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue192/Migrations/ApplicationDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using Issue192.DataLayer; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 7 | 8 | #nullable disable 9 | 10 | namespace Issue192.Migrations 11 | { 12 | [DbContext(typeof(ApplicationDbContext))] 13 | partial class ApplicationDbContextModelSnapshot : ModelSnapshot 14 | { 15 | protected override void BuildModel(ModelBuilder modelBuilder) 16 | { 17 | #pragma warning disable 612, 618 18 | modelBuilder 19 | .HasAnnotation("ProductVersion", "6.0.11") 20 | .HasAnnotation("Relational:MaxIdentifierLength", 128); 21 | 22 | SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1); 23 | 24 | modelBuilder.Entity("Issue192.Entities.Person", b => 25 | { 26 | b.Property("Id") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("int"); 29 | 30 | SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1); 31 | 32 | b.Property("Name") 33 | .HasColumnType("nvarchar(max)"); 34 | 35 | b.HasKey("Id"); 36 | 37 | b.ToTable("People"); 38 | }); 39 | #pragma warning restore 612, 618 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue192/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue192/_01-add_migrations.cmd: -------------------------------------------------------------------------------- 1 | For /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c_%%a_%%b) 2 | For /f "tokens=1-2 delims=/:" %%a in ("%TIME: =0%") do (set mytime=%%a%%b) 3 | dotnet tool update --global dotnet-ef --version 7.0.0 4 | dotnet build 5 | dotnet ef migrations add V%mydate%_%mytime% --context ApplicationDbContext 6 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue192/_02-dotnet_run.bat: -------------------------------------------------------------------------------- 1 | dotnet watch run -------------------------------------------------------------------------------- /src/Tests/Issues/Issue192/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Debug", 6 | "Microsoft": "Debug", 7 | "Microsoft.Hosting.Lifetime": "Debug" 8 | } 9 | }, 10 | "AllowedHosts": "*", 11 | "ConnectionStrings": { 12 | "ApplicationDbContextConnection": "Server=(localdb)\\mssqllocaldb;Initial Catalog=Issue192;AttachDBFilename=%CONTENTROOTPATH%\\App_Data\\Issue192.mdf;Trusted_Connection=True;" 13 | }, 14 | "RedisConfiguration": "localhost:6379" 15 | } 16 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue4SpatialType/App_Data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/Issues/Issue4SpatialType/App_Data/.gitkeep -------------------------------------------------------------------------------- /src/Tests/Issues/Issue4SpatialType/DataLayer/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | using Issue4SpatialType.Entities; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Logging; 4 | 5 | namespace Issue4SpatialType.DataLayer 6 | { 7 | public class ApplicationDbContext : DbContext 8 | { 9 | public ApplicationDbContext(DbContextOptions options) 10 | : base(options) 11 | { 12 | } 13 | 14 | public DbSet People { get; set; } 15 | public DbSet Products { get; set; } 16 | 17 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 18 | { 19 | optionsBuilder 20 | .UseLoggerFactory(LoggerFactory.Create(x => x 21 | .AddConsole() 22 | .AddFilter(y => y >= LogLevel.Debug))) 23 | .EnableSensitiveDataLogging() 24 | .EnableDetailedErrors(); 25 | 26 | base.OnConfiguring(optionsBuilder); 27 | } 28 | 29 | protected override void OnModelCreating(ModelBuilder modelBuilder) 30 | { 31 | modelBuilder 32 | .Entity(entityBuilder => 33 | { 34 | entityBuilder.HasKey(x => x.Id); 35 | entityBuilder.Property(x => x.Id).ValueGeneratedOnAdd(); 36 | }); 37 | 38 | modelBuilder 39 | .Entity(entityBuilder => 40 | { 41 | entityBuilder.HasKey(x => x.Id); 42 | entityBuilder.Property(x => x.Id).ValueGeneratedOnAdd(); 43 | }); 44 | 45 | base.OnModelCreating(modelBuilder); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue4SpatialType/DataLayer/MsSqlContextFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Design; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Configuration; 4 | using System; 5 | using System.IO; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace Issue4SpatialType.DataLayer 9 | { 10 | public class MsSqlContextFactory : IDesignTimeDbContextFactory 11 | { 12 | public ApplicationDbContext CreateDbContext(string[] args) 13 | { 14 | var services = new ServiceCollection(); 15 | 16 | var basePath = Directory.GetCurrentDirectory(); 17 | Console.WriteLine($"Using `{basePath}` as the ContentRootPath"); 18 | var configuration = new ConfigurationBuilder() 19 | .SetBasePath(basePath) 20 | .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) 21 | .Build(); 22 | services.AddSingleton(_ => configuration); 23 | 24 | var optionsBuilder = new DbContextOptionsBuilder(); 25 | optionsBuilder.UseSqlServer(EFServiceProvider.GetConnectionString(basePath, configuration), 26 | builder => builder.UseNetTopologySuite()); 27 | return new ApplicationDbContext(optionsBuilder.Options); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue4SpatialType/Entities/Person.cs: -------------------------------------------------------------------------------- 1 | namespace Issue4SpatialType.Entities 2 | { 3 | public class Person 4 | { 5 | public int Id { get; set; } 6 | public string Name { get; set; } 7 | } 8 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue4SpatialType/Entities/Product.cs: -------------------------------------------------------------------------------- 1 | using NetTopologySuite.Geometries; 2 | 3 | namespace Issue4SpatialType.Entities 4 | { 5 | public class Product 6 | { 7 | public int Id { get; set; } 8 | public Point Location { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue4SpatialType/Migrations/20200304112357_V2020_03_04_1453.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using Issue4SpatialType.DataLayer; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | using NetTopologySuite.Geometries; 9 | 10 | namespace Issue4SpatialType.Migrations 11 | { 12 | [DbContext(typeof(ApplicationDbContext))] 13 | [Migration("20200304112357_V2020_03_04_1453")] 14 | partial class V2020_03_04_1453 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .HasAnnotation("ProductVersion", "3.1.1") 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 22 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 23 | 24 | modelBuilder.Entity("Issue4SpatialType.Entities.Person", b => 25 | { 26 | b.Property("Id") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("int") 29 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 30 | 31 | b.Property("Name") 32 | .HasColumnType("nvarchar(max)"); 33 | 34 | b.HasKey("Id"); 35 | 36 | b.ToTable("People"); 37 | }); 38 | 39 | modelBuilder.Entity("Issue4SpatialType.Entities.Product", b => 40 | { 41 | b.Property("Id") 42 | .ValueGeneratedOnAdd() 43 | .HasColumnType("int") 44 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 45 | 46 | b.Property("Location") 47 | .HasColumnType("geography"); 48 | 49 | b.HasKey("Id"); 50 | 51 | b.ToTable("Products"); 52 | }); 53 | #pragma warning restore 612, 618 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue4SpatialType/Migrations/20200304112357_V2020_03_04_1453.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | using NetTopologySuite.Geometries; 3 | 4 | namespace Issue4SpatialType.Migrations 5 | { 6 | public partial class V2020_03_04_1453 : Migration 7 | { 8 | protected override void Up(MigrationBuilder migrationBuilder) 9 | { 10 | migrationBuilder.CreateTable( 11 | name: "People", 12 | columns: table => new 13 | { 14 | Id = table.Column(nullable: false) 15 | .Annotation("SqlServer:Identity", "1, 1"), 16 | Name = table.Column(nullable: true) 17 | }, 18 | constraints: table => 19 | { 20 | table.PrimaryKey("PK_People", x => x.Id); 21 | }); 22 | 23 | migrationBuilder.CreateTable( 24 | name: "Products", 25 | columns: table => new 26 | { 27 | Id = table.Column(nullable: false) 28 | .Annotation("SqlServer:Identity", "1, 1"), 29 | Location = table.Column(nullable: true) 30 | }, 31 | constraints: table => 32 | { 33 | table.PrimaryKey("PK_Products", x => x.Id); 34 | }); 35 | } 36 | 37 | protected override void Down(MigrationBuilder migrationBuilder) 38 | { 39 | migrationBuilder.DropTable( 40 | name: "People"); 41 | 42 | migrationBuilder.DropTable( 43 | name: "Products"); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue4SpatialType/Migrations/ApplicationDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using Issue4SpatialType.DataLayer; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 7 | using NetTopologySuite.Geometries; 8 | 9 | namespace Issue4SpatialType.Migrations 10 | { 11 | [DbContext(typeof(ApplicationDbContext))] 12 | partial class ApplicationDbContextModelSnapshot : ModelSnapshot 13 | { 14 | protected override void BuildModel(ModelBuilder modelBuilder) 15 | { 16 | #pragma warning disable 612, 618 17 | modelBuilder 18 | .HasAnnotation("ProductVersion", "3.1.1") 19 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 20 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 21 | 22 | modelBuilder.Entity("Issue4SpatialType.Entities.Person", b => 23 | { 24 | b.Property("Id") 25 | .ValueGeneratedOnAdd() 26 | .HasColumnType("int") 27 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 28 | 29 | b.Property("Name") 30 | .HasColumnType("nvarchar(max)"); 31 | 32 | b.HasKey("Id"); 33 | 34 | b.ToTable("People"); 35 | }); 36 | 37 | modelBuilder.Entity("Issue4SpatialType.Entities.Product", b => 38 | { 39 | b.Property("Id") 40 | .ValueGeneratedOnAdd() 41 | .HasColumnType("int") 42 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 43 | 44 | b.Property("Location") 45 | .HasColumnType("geography"); 46 | 47 | b.HasKey("Id"); 48 | 49 | b.ToTable("Products"); 50 | }); 51 | #pragma warning restore 612, 618 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue4SpatialType/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using EFCoreSecondLevelCacheInterceptor; 3 | using Microsoft.EntityFrameworkCore; 4 | using Issue4SpatialType.Entities; 5 | using NetTopologySuite; 6 | using NetTopologySuite.Geometries; 7 | using System; 8 | 9 | namespace Issue4SpatialType 10 | { 11 | class Program 12 | { 13 | static void Main(string[] args) 14 | { 15 | //SqlServerTypes.Utilities.LoadNativeAssemblies(AppContext.BaseDirectory); 16 | 17 | initDb(); 18 | 19 | EFServiceProvider.RunInContext(context => 20 | { 21 | var cachedProducts = context.Products.Cacheable().ToList(); 22 | cachedProducts = context.Products.Cacheable().ToList(); 23 | foreach (var product in cachedProducts) 24 | { 25 | Console.WriteLine($"{product.Id}, {product.Location}"); 26 | } 27 | }); 28 | } 29 | 30 | private static void initDb() 31 | { 32 | EFServiceProvider.RunInContext(context => 33 | { 34 | context.Database.Migrate(); 35 | 36 | if (!context.Products.Any()) 37 | { 38 | context.People.Add(new Person 39 | { 40 | Name = "Bill" 41 | }); 42 | 43 | var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326); 44 | context.Products.AddRange( 45 | new Product { Location = geometryFactory.CreatePoint(new Coordinate(27.175015, 78.042155)) }, 46 | new Product { Location = geometryFactory.CreatePoint(new Coordinate(27.175015, 78.042155)) }, 47 | new Product { Location = geometryFactory.CreatePoint(new Coordinate(27.175015, 78.042155)) }); 48 | 49 | context.SaveChanges(); 50 | } 51 | }); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue4SpatialType/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue4SpatialType/_01-add_migrations.cmd: -------------------------------------------------------------------------------- 1 | For /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c_%%a_%%b) 2 | For /f "tokens=1-2 delims=/:" %%a in ("%TIME: =0%") do (set mytime=%%a%%b) 3 | dotnet tool update --global dotnet-ef --version 6.0.7 4 | dotnet build 5 | dotnet ef migrations add V%mydate%_%mytime% --context ApplicationDbContext 6 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue4SpatialType/_02-dotnet_run.bat: -------------------------------------------------------------------------------- 1 | dotnet watch run -------------------------------------------------------------------------------- /src/Tests/Issues/Issue4SpatialType/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Debug", 6 | "Microsoft": "Debug", 7 | "Microsoft.Hosting.Lifetime": "Debug" 8 | } 9 | }, 10 | "AllowedHosts": "*", 11 | "ConnectionStrings": { 12 | "ApplicationDbContextConnection": "Server=(localdb)\\mssqllocaldb;Initial Catalog=Issue4SpatialType;AttachDBFilename=%CONTENTROOTPATH%\\App_Data\\Issue4SpatialType.mdf;Trusted_Connection=True;" 13 | }, 14 | "RedisConfiguration": "localhost:6379" 15 | } 16 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue9SQLiteInt32/App_Data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/Issues/Issue9SQLiteInt32/App_Data/.gitkeep -------------------------------------------------------------------------------- /src/Tests/Issues/Issue9SQLiteInt32/App_Data/TestDb.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/Issues/Issue9SQLiteInt32/App_Data/TestDb.sqlite -------------------------------------------------------------------------------- /src/Tests/Issues/Issue9SQLiteInt32/DataLayer/SqliteContextFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Design; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Configuration; 4 | using System; 5 | using System.IO; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace Issue9SQLiteInt32.DataLayer 9 | { 10 | public class SqliteContextFactory : IDesignTimeDbContextFactory 11 | { 12 | public ApplicationDbContext CreateDbContext(string[] args) 13 | { 14 | var services = new ServiceCollection(); 15 | 16 | var basePath = Directory.GetCurrentDirectory(); 17 | Console.WriteLine($"Using `{basePath}` as the ContentRootPath"); 18 | var configuration = new ConfigurationBuilder() 19 | .SetBasePath(basePath) 20 | .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) 21 | .Build(); 22 | services.AddSingleton(_ => configuration); 23 | 24 | var optionsBuilder = new DbContextOptionsBuilder(); 25 | optionsBuilder.UseSqlite(EFServiceProvider.GetConnectionString(basePath, configuration)); 26 | return new ApplicationDbContext(optionsBuilder.Options); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue9SQLiteInt32/Entities/Person.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | 4 | namespace Issue9SQLiteInt32.Entities 5 | { 6 | public class Person 7 | { 8 | public int Id { get; set; } 9 | 10 | public string Name { get; set; } 11 | 12 | public DateTime AddDate { get; set; } 13 | 14 | public DateTime? UpdateDate { get; set; } 15 | 16 | public long Points { get; set; } 17 | 18 | public bool IsActive { get; set; } 19 | 20 | public byte ByteValue { get; set; } 21 | 22 | public char CharValue { get; set; } 23 | 24 | public DateTimeOffset DateTimeOffsetValue { get; set; } 25 | 26 | public decimal DecimalValue { get; set; } 27 | 28 | public double DoubleValue { set; get; } 29 | 30 | public float FloatValue { set; get; } 31 | 32 | public Guid GuidValue { set; get; } 33 | 34 | public TimeSpan TimeSpanValue { set; get; } 35 | 36 | public short ShortValue { set; get; } 37 | 38 | public byte[] ByteArrayValue { get; set; } 39 | 40 | public uint UintValue { set; get; } 41 | 42 | public ulong UlongValue { set; get; } 43 | 44 | public ulong UshortValue { set; get; } 45 | 46 | [Column(TypeName = "numeric")] 47 | public decimal NumericDecimalValue { get; set; } 48 | } 49 | } -------------------------------------------------------------------------------- /src/Tests/Issues/Issue9SQLiteInt32/Issue9SQLiteInt32.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net9.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue9SQLiteInt32/Migrations/20200322180442_V2020_03_22_2234.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | namespace Issue9SQLiteInt32.Migrations 5 | { 6 | public partial class V2020_03_22_2234 : Migration 7 | { 8 | protected override void Up(MigrationBuilder migrationBuilder) 9 | { 10 | migrationBuilder.CreateTable( 11 | name: "People", 12 | columns: table => new 13 | { 14 | Id = table.Column(nullable: false) 15 | .Annotation("Sqlite:Autoincrement", true), 16 | Name = table.Column(nullable: true), 17 | AddDate = table.Column(nullable: false), 18 | UpdateDate = table.Column(nullable: true), 19 | Points = table.Column(nullable: false), 20 | IsActive = table.Column(nullable: false), 21 | ByteValue = table.Column(nullable: false), 22 | CharValue = table.Column(nullable: false), 23 | DateTimeOffsetValue = table.Column(nullable: false), 24 | DecimalValue = table.Column(nullable: false), 25 | DoubleValue = table.Column(nullable: false), 26 | FloatValue = table.Column(nullable: false), 27 | GuidValue = table.Column(nullable: false), 28 | TimeSpanValue = table.Column(nullable: false), 29 | ShortValue = table.Column(nullable: false), 30 | ByteArrayValue = table.Column(nullable: true), 31 | UintValue = table.Column(nullable: false), 32 | UlongValue = table.Column(nullable: false), 33 | UshortValue = table.Column(nullable: false) 34 | }, 35 | constraints: table => 36 | { 37 | table.PrimaryKey("PK_People", x => x.Id); 38 | }); 39 | } 40 | 41 | protected override void Down(MigrationBuilder migrationBuilder) 42 | { 43 | migrationBuilder.DropTable( 44 | name: "People"); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue9SQLiteInt32/Migrations/20200322194455_V2020_03_23_0014.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace Issue9SQLiteInt32.Migrations 4 | { 5 | public partial class V2020_03_23_0014 : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | name: "NumericDecimalValue", 11 | table: "People", 12 | type: "numeric", 13 | nullable: false, 14 | defaultValue: 0m); 15 | } 16 | 17 | protected override void Down(MigrationBuilder migrationBuilder) 18 | { 19 | migrationBuilder.DropColumn( 20 | name: "NumericDecimalValue", 21 | table: "People"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Tests/Issues/Issue9SQLiteInt32/_0-restore.bat: -------------------------------------------------------------------------------- 1 | rmdir /S /Q bin 2 | rmdir /S /Q obj 3 | dotnet restore 4 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue9SQLiteInt32/_01-add_migrations.cmd: -------------------------------------------------------------------------------- 1 | For /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c_%%a_%%b) 2 | For /f "tokens=1-2 delims=/:" %%a in ("%TIME: =0%") do (set mytime=%%a%%b) 3 | dotnet tool update --global dotnet-ef --version 9.0.0 4 | dotnet build 5 | dotnet ef migrations add V%mydate%_%mytime% --context ApplicationDbContext 6 | pause -------------------------------------------------------------------------------- /src/Tests/Issues/Issue9SQLiteInt32/_02-dotnet_run.bat: -------------------------------------------------------------------------------- 1 | dotnet watch run -------------------------------------------------------------------------------- /src/Tests/Issues/Issue9SQLiteInt32/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Debug", 6 | "Microsoft": "Debug", 7 | "Microsoft.Hosting.Lifetime": "Debug" 8 | } 9 | }, 10 | "AllowedHosts": "*", 11 | "ConnectionStrings": { 12 | "ApplicationDbContextConnection": "Data Source=%CONTENTROOTPATH%\\App_Data\\TestDb.sqlite" 13 | }, 14 | "RedisConfiguration": "localhost:6379" 15 | } 16 | -------------------------------------------------------------------------------- /src/Tests/redis-64.3.0.503/redis-benchmark.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/redis-64.3.0.503/redis-benchmark.exe -------------------------------------------------------------------------------- /src/Tests/redis-64.3.0.503/redis-check-aof.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/redis-64.3.0.503/redis-check-aof.exe -------------------------------------------------------------------------------- /src/Tests/redis-64.3.0.503/redis-check-dump.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/redis-64.3.0.503/redis-check-dump.exe -------------------------------------------------------------------------------- /src/Tests/redis-64.3.0.503/redis-cli.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/redis-64.3.0.503/redis-cli.exe -------------------------------------------------------------------------------- /src/Tests/redis-64.3.0.503/redis-server.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VahidN/EFCoreSecondLevelCacheInterceptor/a9205d00ad111dda3cbe2147e1d14167a0f22b00/src/Tests/redis-64.3.0.503/redis-server.exe -------------------------------------------------------------------------------- /src/Tests/redis-64.3.0.503/ref.txt: -------------------------------------------------------------------------------- 1 | https://www.nuget.org/packages/Redis-64/ -------------------------------------------------------------------------------- /tag-it.bat: -------------------------------------------------------------------------------- 1 | git tag -a 4.2.2 -m "Published 4.2.2 to nuget.org" 2 | git push --follow-tags 3 | pause -------------------------------------------------------------------------------- /update-dependencies.bat: -------------------------------------------------------------------------------- 1 | dotnet restore 2 | dotnet list package --outdated 3 | dotnet restore 4 | pause --------------------------------------------------------------------------------