Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions .github/workflows/build-samples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ on:
- "ef-core/advanced-modeling-performance/**"
- "ef-core/modern-data-access-dotnet/**"
- "ef-core/multitenancy-softdelete-auditing/**"
- "ef-core/testing-sqlite-inmemory-vs-inmemory/**"
- ".github/workflows/build-samples.yml"

pull_request:
Expand Down Expand Up @@ -60,6 +61,7 @@ on:
- "ef-core/advanced-modeling-performance/**"
- "ef-core/modern-data-access-dotnet/**"
- "ef-core/multitenancy-softdelete-auditing/**"
- "ef-core/testing-sqlite-inmemory-vs-inmemory/**"
- ".github/workflows/build-samples.yml"

workflow_dispatch:
Expand Down Expand Up @@ -1870,3 +1872,143 @@ jobs:
exit 1
fi

test-ef-core-provider-contrast:
name: Test EF Core provider contrast sample
runs-on: ubuntu-latest

permissions:
contents: read

steps:
- name: Check out repository
uses: actions/checkout@v5

- name: Install .NET 10 SDK
uses: actions/setup-dotnet@v5
with:
dotnet-version: "10.0.x"

- name: Restore
run: >
dotnet restore
ef-core/testing-sqlite-inmemory-vs-inmemory/EfCoreProviderContrastMinimal.slnx

- name: Build
run: >
dotnet build
ef-core/testing-sqlite-inmemory-vs-inmemory/EfCoreProviderContrastMinimal.slnx
--configuration Release
--no-restore

- name: Test
run: >
dotnet test
ef-core/testing-sqlite-inmemory-vs-inmemory/EfCoreProviderContrastMinimal.slnx
--configuration Release
--no-build

- name: Verify EF Core provider baseline
shell: bash
run: |
project="ef-core/testing-sqlite-inmemory-vs-inmemory/src/EfCoreProviderContrastMinimal/EfCoreProviderContrastMinimal.csproj"

test "$(
grep \
--count \
'<PackageReference' \
"${project}"
)" = "2"

grep \
--fixed-strings \
'Include="Microsoft.EntityFrameworkCore.InMemory"' \
"${project}"

grep \
--fixed-strings \
'Include="Microsoft.EntityFrameworkCore.Sqlite"' \
"${project}"

test "$(
grep \
--count \
'Version="10.0.11"' \
"${project}"
)" = "2"

- name: Verify exact provider-contrast output
shell: bash
run: |
output="$(
dotnet run \
--project ef-core/testing-sqlite-inmemory-vs-inmemory/src/EfCoreProviderContrastMinimal/EfCoreProviderContrastMinimal.csproj \
--configuration Release \
--no-build
)"

expected="$(
printf '%s\n' \
'EF Core Test Provider Contrast Lab' \
'Unique index: InMemory=accepted | SQLite=rejected' \
'Foreign key: InMemory=accepted | SQLite=rejected' \
'Transaction: InMemory=unsupported | SQLite=rollback-ok' \
'Database cascade: InMemory=orphan-remains | SQLite=child-removed' \
'Guidance: relational behavior -> production provider when practical; SQLite remains a test double.'
)"

printf '%s\n' "${output}"

if [[ "${output}" != "${expected}" ]]; then
echo "Unexpected provider-contrast output."
exit 1
fi

- name: Verify provider-contrast boundaries
shell: bash
run: |
sample="ef-core/testing-sqlite-inmemory-vs-inmemory"

grep -R \
--include='*.cs' \
--include='*.csproj' \
--fixed-strings \
'Foreign Keys=True' \
"${sample}/src"

grep -R \
--include='*.cs' \
--include='*.csproj' \
--fixed-strings \
'InMemoryDatabaseRoot' \
"${sample}/src"

if grep -R \
--include='*.cs' \
--include='*.csproj' \
-E \
'TransactionIgnoredWarning|BenchmarkDotNet|Stopwatch' \
"${sample}/src"; then
echo "Unexpected ignored-transaction or benchmark code found."
exit 1
fi

- name: Verify no generated database artifacts
shell: bash
run: |
if find \
ef-core/testing-sqlite-inmemory-vs-inmemory \
-type f \
\( \
-name '*.db' \
-o -name '*.sqlite' \
-o -name '*.sqlite3' \
\) \
-print \
-quit |
grep \
--quiet \
.; then
echo "Generated SQLite database file found."
exit 1
fi

23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Each sample folder contains a focused implementation of one tutorial topic. The
| [`ef-core/advanced-modeling-performance`](ef-core/advanced-modeling-performance/) | Focused .NET 10 / EF Core 10 relational-data companion demonstrating DTO projection, no-tracking reads, a compiled hot-path query, named soft-delete filtering, ExecuteUpdate, ExecuteDelete, and explicit change-tracker caveats with deterministic SQLite tests | [EF Core Advanced Modeling & Performance: Owned Types, Converters, JSON/Temporal Tables, Compiled Queries](https://www.dotnet-guide.com/tutorials/ef-core/advanced-modeling-performance/) |
| [`ef-core/modern-data-access-dotnet`](ef-core/modern-data-access-dotnet/) | Focused .NET 10 / EF Core 10 relationship-loading companion demonstrating one-to-many and many-to-many modeling, an intentional N+1 baseline, eager and filtered Include, split-query loading, explicit loading, SELECT-command counting, and deterministic SQLite verification | [EF Core 8 Fundamentals: Modern Data Access with .NET 8](https://www.dotnet-guide.com/tutorials/ef-core/modern-data-access-dotnet/) |
| [`ef-core/multitenancy-softdelete-auditing`](ef-core/multitenancy-softdelete-auditing/) | Focused .NET 10 / EF Core 10 multi-tenant data guardrail companion demonstrating fail-closed tenant filtering, named soft-delete filtering, tenant-scoped composite identity, SaveChanges interception, automatic audit metadata, selective deleted-record access, cross-tenant mutation rejection, and deterministic SQLite isolation tests | [EF Core 8 Multi-Tenancy: Tenant Isolation, Soft Deletes, Audit Trails & Query Filters](https://www.dotnet-guide.com/tutorials/ef-core/multitenancy-softdelete-auditing/) |
| [`ef-core/testing-sqlite-inmemory-vs-inmemory`](ef-core/testing-sqlite-inmemory-vs-inmemory/) | Focused .NET 10 / EF Core 10 provider-contrast companion demonstrating how SQLite in-memory and the EF Core InMemory provider differ on unique constraints, foreign keys, transactions, and database-side cascades while explicitly treating SQLite as a test double rather than production-provider parity | [EF Core Testing: SQLite In-Memory vs InMemory Provider — Which One Can You Actually Trust?](https://www.dotnet-guide.com/tutorials/ef-core/testing-sqlite-inmemory-vs-inmemory/) |

## Companion articles
- [Common Microsoft.Extensions.AI mistakes](https://www.dotnet-guide.com/articles/dotnet-ai/microsoft-extensions-ai-common-mistakes/)
Expand Down Expand Up @@ -514,7 +515,7 @@ tutorials/
| `-- EfCoreRelationshipsMinimal.Tests/
| |-- EfCoreRelationshipsMinimal.Tests.csproj
| `-- EfCoreRelationshipsTests.cs
| `-- multitenancy-softdelete-auditing/
| |-- multitenancy-softdelete-auditing/
| |-- EfCoreTenantGuardrailsMinimal.slnx
| |-- README.md
| |-- src/
Expand All @@ -538,6 +539,26 @@ tutorials/
| `-- EfCoreTenantGuardrailsMinimal.Tests/
| |-- EfCoreTenantGuardrailsMinimal.Tests.csproj
| `-- TenantGuardrailTests.cs
| `-- testing-sqlite-inmemory-vs-inmemory/
| |-- EfCoreProviderContrastMinimal.slnx
| |-- README.md
| |-- src/
| | `-- EfCoreProviderContrastMinimal/
| | |-- EfCoreProviderContrastMinimal.csproj
| | |-- Program.cs
| | |-- Data/
| | | `-- ProviderDbContext.cs
| | |-- Models/
| | | `-- ProviderModels.cs
| | |-- Providers/
| | | |-- InMemoryTestDatabase.cs
| | | `-- SqliteTestDatabase.cs
| | `-- Services/
| | `-- ProviderContrast.cs
| `-- tests/
| `-- EfCoreProviderContrastMinimal.Tests/
| |-- EfCoreProviderContrastMinimal.Tests.csproj
| `-- ProviderContrastTests.cs
|-- .github/
| `-- workflows/
| `-- build-samples.yml
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<Solution>
<Project Path="src/EfCoreProviderContrastMinimal/EfCoreProviderContrastMinimal.csproj" />
<Project Path="tests/EfCoreProviderContrastMinimal.Tests/EfCoreProviderContrastMinimal.Tests.csproj" />
</Solution>
Loading
Loading