3.9 KiB
Yak 01 — C# solution: the BEFORE situation (DB-backed domain classes)
Context
This exercise illustrates the transition from domain classes that inherit a DB
base class (EF-style, or active-record-like) to plain domain objects + DTOs.
See before-after-dto.mmd (and before-after-dto-sketch.png) for the diagram
this yak implements in C#:
DbContext— the database context (EF fake)DbBase— base class with anId; depends onDbContextClient,Order— domain classes inheritingDbBaseWebApp— consumes the domain classes directly
Yak 02 will implement the "after" situation in the same solution.
Tech constraints
-
.NET SDK: target net8.0 (adjust if only another SDK is installed; note it in the commit message).
-
Fake the EF magic — do NOT add real EF Core. The point of the exercise is the shape of the dependencies, not EF's behavior. A fake
DbContextkeeps the project pure managed code: no native binaries, no SQLite, no provider quirks → guaranteed cross-platform (Windows/macOS/Linux). -
Tests: xUnit, one test project.
-
Solution layout:
db-subclass-to-dto.sln src/ Before/ (net8.0 class library, namespace Before.*) After/ (net8.0 class library, namespace After.*) ← created in Yak 02 tests/ BeforeAfter.Tests/ (net8.0 xUnit project)Yak 01 only creates the solution, the
Before/project, and the test project (plus an emptyAfter/project so the solution shape is final).
"Magic" to fake on DbBase / DbContext
Simulate EF's change tracker with a minimal fake:
DbContextholds a registration dictionary of entities it knows about.DbContext.Save()iterates trackedDbBaseentities: assigns a freshGuidIdto any entity whoseIdisGuid.Empty, and records it.DbBasecarries a back-reference to its owningDbContext(active-record-style "I know which context created me") — this is the dependency leak the exercise wants to expose.Clienthas anOrderscollection;Orderhas aClientback-reference. Adding an order toclient.Orderssetsorder.Client(mimic EF navigation fix-up).- A
WebApptype with methods that consumeClient/Orderdirectly, including one that demonstrates the leak: reaching theDbContextthrough a domain object (e.g.client.DbContext).
Keep the fake small; this is an illustration, not an ORM.
Required tests (BeforeTests)
At minimum:
ClientandOrderderive fromDbBase(typeof(DbBase).IsAssignableFrom(typeof(Client))etc.).- New
Client/Orderinstances haveId == Guid.Empty. DbContext.Save()assigns fresh, distinctGuidids to saved entities (the faked EF magic).- Saved entities are registered with their
DbContext(reachable via the back-reference). - Relation fix-up:
client.Orders.Add(order)setsorder.Client == client. - The leak: from a bare
Client, you can reach theDbContext(client.DbContextis non-null after save) — assert this explicitly, comment that this is exactly what the "after" situation removes. WebAppmethods work on the domain classes directly.
Acceptance criteria
dotnet build db-subclass-to-dto.slnsucceeds with 0 warnings.dotnet test db-subclass-to-dto.slnsucceeds; all tests pass.- No NuGet packages beyond xUnit's default set (no EF Core, no SQLite, no AutoMapper).
- Code + tests committed with a message referencing this yak.
Open questions (answer before starting, defaults in parens)
- Target framework net8.0 or something else? (net8.0)
- Fake DbContext only, or do you also want a variant using real EF Core +
Microsoft.Data.Sqlite(bundled native lib — still no install needed on Windows, but adds NuGet/ABI surface)? (fake only) - Any naming/style preference (file-scoped namespaces, records vs classes)? (file-scoped namespaces; plain classes)