Yak: csharp before situation (Yak 01) — DB-backed domain classes

Add the C# BEFORE situation: a fake-EF DbContext + DbBase that Client/Order
inherit, the active-record DbContext back-reference (the dependency leak),
navigation fix-up on Client.Orders, and a WebApp that consumes the domain
classes directly. Adds an empty After project so the solution shape is final,
and an xUnit BeforeTests suite covering the required assertions.

- db-subclass-to-dto.sln (classic .sln; SDK 10 defaults to .slnx which breaks run-tests.sh)
- src/Before: DbBase, DbContext, Client (+ClientOrders fix-up), Order, WebApp
- src/After: empty placeholder (filled in Yak 02)
- tests/BeforeAfter.Tests/BeforeTests.cs: 8 tests (7 required + 1 companion)
This commit is contained in:
2026-09-11 13:03:09 +01:00
parent 7e38f67e0b
commit 463245288a
10 changed files with 454 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
namespace Before;
/// <summary>
/// Base class for every DB-backed domain object. Fakes the active-record part
/// of EF: each entity carries its own <see cref="Id"/> and, once it has been
/// created/saved through a context, a back-reference to that context.
///
/// <see cref="DbContext"/> is the dependency this base class leaks. The
/// "after" situation (Yak 02) removes this inheritance entirely — domain
/// objects become plain POCOs that know nothing about a DbContext.
/// </summary>
public class DbBase
{
/// <summary>
/// Primary key. Fresh (unsaved) entities have <see cref="Guid.Empty"/>;
/// <see cref="DbContext.Save"/> assigns a real id, faking EF's identity
/// generation.
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// Active-record back-reference: "I know which context created me". This
/// is the leak the exercise exposes — from a plain domain object you can
/// reach straight into the persistence layer. <c>internal set</c> because
/// only the owning <see cref="DbContext"/> may (re)assign it; consumers
/// (including the WebApp, and the tests) can only read it.
/// </summary>
public DbContext? DbContext { get; internal set; }
}