Chapter 25 · Production Architecture, DDD/CQRS Integration, Reliability, and Capstone

Capstone: Design, Implement, Test, Tune, Secure, Deploy, and Defend a Production EF Core Data Layer

Require an evidence-backed ServiceHub production data-layer defense spanning model, SQL, tracking, concurrency, transactions, migrations, tenancy, security, tests, observability, performance, deployment and intentional non-EF paths.

Advanced210–300 minutesproduction capstone defenseEF Core 10.0.11 · Microsoft.EntityFrameworkCore.Sqlite 10.0.11 · dotnet-ef 10.0.11 · .NET 10.0.11 · SDK 10.0.400Mandatory free local SQLite path · Dapper 2.1.79 optional · production-like server provider optionalArchitecture/package/platform status reviewed: August 27, 2026

Learning outcomes

01

Assemble a complete ServiceHub production data layer from the course decisions rather than starting a new toy model.

02

Defend the provider, model, loading/tracking, concurrency, transaction and migration choices with observable evidence.

03

Prove tenant isolation/security with adversarial tests and least-privilege deployment/runtime separation.

04

Benchmark one hot read path with realistic data, query tags and database plan evidence.

05

Operate the design with health checks, metrics, outbox/backlog visibility, backup/restore and incident runbooks.

06

Explain where EF Core is intentionally not used and why that boundary improves the system.

1. Capstone brief: defend ServiceHub as if another team must operate it

The final deliverable is not “a CRUD API that runs.” You are the owner of a multi-tenant ServiceHub data layer that another team must deploy, test, monitor and repair. Every major decision needs an artifact: model configuration, migration SQL, generated command, tracker evidence, test result, execution plan, metric, runbook or explicit provider constraint.

Completion standard

A design claim without observable evidence is incomplete. “EF handles it” is not evidence; show what EF generated, what the provider/database enforced, and what your tests/operations prove.

2. Required architecture: one portable core, explicit provider boundaries

Use the established SQLite mandatory path for a free local capstone and optionally qualify SQL Server/PostgreSQL/MySQL with the provider matrix from Chapters 19–21. Keep provider-specific features behind intentional adapters/configuration, not accidental LINQ scattered across the application.

Concern Required capstone choice
Aggregate/write model Encapsulated WorkOrder + ServiceAddress + Revision + tenant/lifecycle invariants
Read model Bounded DTO projection; optional SQL/Dapper hot path only with evidence
Consistency SaveChanges/explicit transaction + optimistic concurrency resolution
Integration Transactional outbox + idempotent relay
Schema Reviewed migrations + deployment artifact + expand/contract plan
Security named tenant filters + authorization + DB constraints/least privilege; optional RLS
Operations health, metrics/logs/traces, slow-query/plan correlation, backup/restore and runbooks

3. The capstone command path

C# · command orchestration sketch
public sealed class ReviseWorkOrderCommandHandler(    ServiceHubContext db,    IWorkOrderRepository orders,    TimeProvider clock){    public async Task HandleAsync(int id, string summary, CancellationToken ct)    {        var order = await orders.LoadForRevisionAsync(id, ct)            ?? throw new KeyNotFoundException();        order.ReviseSummary(summary, clock); // invariant + Revision + domain event        await db.SaveChangesAsync(ct);        // aggregate + outbox in one transaction    }}
Evidence expected from SQLite lab
UPDATE "work_orders"SET "summary" = @summary, "revision" = @newRevisionWHERE "work_order_id" = @id  AND "revision" = @originalRevision;INSERT INTO "outbox_messages" (...)VALUES (...);-- both participate in the same SaveChanges transaction

The review must explain tenant filter/write ownership, the original-versus-new revision predicate, outbox atomicity and how a concurrency conflict is surfaced/resolved.

4. The capstone read path must prove shape and plan

C# · tagged bounded queue query
var query = db.WorkOrders    .TagWith("ServiceHub.Capstone.Queue.v1")    .AsNoTracking()    .Where(w => w.Priority >= 3)    .OrderByDescending(w => w.Priority)    .ThenBy(w => w.OpenedUtc)    .Take(100)    .Select(w => new WorkOrderQueueRow(        w.Id, w.WorkOrderNumber, w.Summary,        w.Priority, w.ServiceAddress.City));Console.WriteLine(query.ToQueryString());var rows = await query.ToListAsync(ct);

Capture the generated SQL, actual row count, data distribution and SQLite EXPLAIN QUERY PLAN (or the production provider’s actual plan tool). If you replace this path with raw SQL/Dapper, repeat the same correctness/security/performance evidence.

5. Test matrix: happy paths are the least interesting rows

Suite Minimum proof
Domain unit invalid summary/transition rejected without database
Relational lightweight FK/unique/tenant constraints + migration-aware SQLite setup
Concurrency two contexts read same Revision; loser gets DbUpdateConcurrencyException
Transaction/outbox forced failure commits neither aggregate nor outbox
Tenant red-team cross-tenant reads/writes/filter bypass/admin path constrained
Provider fidelity production-like engine translation/migration tests where applicable
Performance bounded regression baseline + plan/query-count evidence
Deployment representative prior schema → current migration + restore/rollback rehearsal

6. Security acceptance criteria

The capstone must keep SQL values parameterized, dynamic query choices allow-listed, credentials out of source/logs, runtime DB identity separate from migration authority where the provider supports roles, sensitive EF logging disabled by default, and tenant isolation enforced in more than one layer. A successful IgnoreQueryFilters admin operation must have explicit authorization and audit evidence.

7. Deliberate failure review: identify architecture smells before launch

Reject or justify these smells
[ ] Generic repository that mirrors every DbSet method[ ] IQueryable exposed to untrusted/API consumers without shape policy[ ] External broker publish inside SavingChanges[ ] Every read materializes tracked aggregates[ ] Dapper/raw SQL bypasses tenant predicate or transaction ownership[ ] ExecuteUpdate used where aggregate events/concurrency tokens are required[ ] App replicas run schema migration on startup by default[ ] Pool/timeout values copied from a blog without target measurements[ ] EnableSensitiveDataLogging enabled in ordinary production[ ] SQLite tests claimed as proof of SQL Server/PostgreSQL semantics[ ] Down migration treated as the backup/rollback plan

Each checked item needs either a repair or a documented, tested reason it is safe in this topology.

8. Production evidence packet

Submit a small evidence bundle alongside the code:

  1. Model: WorkOrder metadata, complex ServiceAddress columns, tenant filters, keys/FKs/indexes and Revision token.
  2. SQL: one command update and one hot query with parameters/tags.
  3. Tracker: before/after DebugView for one aggregate change.
  4. Migrations: reviewed SQL/bundle plan, migration-history state and expand/contract note.
  5. Tests: concurrency, transaction/outbox, tenant red-team and provider-fidelity results.
  6. Performance: data volume/distribution, warmup/cache disclosure, query plan and bounded latency baseline.
  7. Operations: dashboard signals, backup/restore evidence and two incident runbooks.

9. Mandatory final lab: design, implement, test, tune, secure and deploy

  1. Start from the accumulated ServiceHub project—not a new sample.
  2. Implement one tenant-aware WorkOrder command with aggregate invariant, Revision and domain event.
  3. Persist its outbox row atomically and run an idempotent local relay.
  4. Implement the bounded queue read; capture SQL and plan; optionally compare Dapper 2.1.79.
  5. Run the Chapter 23 migration/concurrency/transaction/query-count/provider tests and Chapter 22 tenant adversarial tests.
  6. Generate a deployment migration artifact and execute it against a disposable environment with a separate deployment configuration.
  7. Run readiness/observability checks, inject one timeout/lock/query-regression incident, and follow the runbook.
  8. Perform a SQLite-aware backup and restore verification for the mandatory local path.
  9. Write a one-page architecture defense: where EF Core is used, where it is not, and which evidence supports every exception.

10. Course completion: the transferable skill is prediction and evidence

You have completed the EF Core path when you can predict the model/query/tracker/write behavior, inspect what EF generates, identify what the provider/database actually guarantees, and choose architecture/operations from evidence. EF Core is neither a black box nor a religion: it is one part of a relational data system whose correctness depends on domain boundaries, SQL semantics, transactions, deployment, security, testing and observability working together.

Check your understanding

  1. What makes the capstone more than a CRUD exercise?
  2. Why must the architecture defense state where EF is not used?
  3. What proves optimistic concurrency?
  4. What proves tenant isolation?
  5. What proves a performance change is real?
  6. When is the course complete?
Review the answers

1. It requires evidence for model/query/write semantics plus concurrency, transactions, migrations, security, tests, performance, observability and deployment/runbooks.

2. Specialized paths may be better served by raw SQL/Dapper/native APIs; making the boundary explicit prevents accidental provider/security/transaction drift.

3. Two independent contexts plus a generated update predicate containing the original token and a deterministic loser conflict.

4. Adversarial tests plus application authorization/filter policy and database constraints/least privilege; optional RLS where supported.

5. Controlled workload/data distribution, generated SQL, plan, repeated measurement and disclosed cache/network/provider conditions.

6. When the learner can predict, observe, test and defend EF/database behavior across development and production operations.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.

\n