Skip to main content
Welcome. This site supports keyboard navigation and screen readers. Press ? at any time for keyboard shortcuts. Press [ to focus the sidebar, ] to focus the content. High-contrast themes are available via the toolbar.
serard@dev00:~/cv

The Premise

You describe what your domain model is. The compiler produces how EF Core configures it.

Entity.Dsl is an attribute-based DSL that decorates POCO classes to define EF Core entities, relationships, and lifecycle semantics. A Roslyn Source Generator reads the attributes at compile time and emits production-ready EF Core configuration, typed repositories, unit-of-work classes, and DI registration — with zero runtime reflection.

This series builds a complete online marketplace domain — stores, products, categories, orders, customers, payments — one concept at a time, showing every attribute and every line of generated code.


Part I: The Pitch

The problem with hand-written EF Core configurations. The Entity.Dsl answer: decorate POCOs, generate everything. The Generation Gap pattern. A single Product entity and its complete generated output — 15 lines in, 250 lines out.

Part II: Source Generators 101

How Entity.Dsl works under the hood. IIncrementalGenerator, ForAttributeWithMetadataName, the 4-stage discovery pipeline, emit models as DTOs, the emitter pattern, incremental caching, diagnostic reporting, and debugging techniques.

Part III: Aggregates and Composition

DDD aggregate boundaries mapped to EF Core delete behavior. [Composition] = Cascade, [Aggregation] = Restrict, [Association] = NoAction. The Order aggregate, Customer references, and Store with its Settings — lifecycle ownership expressed in one attribute.

Part IV: Value Objects and Owned Types

Three mapping strategies for non-entity types: [Owned] (OwnsOne, separate table, JSON column), [ValueObject]/[ComplexType] (ComplexProperty), and regular [Entity]. Address, Money, enums, computed columns, backing fields, and the decision matrix.

Part V: Associations and Self-References

Many-to-many done right. [AssociationClass] with payload, auto-generated composite keys, skip navigations, and IAssociationRepository. Self-referencing categories with [SelfReference] for tree structures.

Part VI: Behaviors

Cross-cutting concerns as composable attributes — Doctrine-style. [Timestampable], [SoftDeletable], [Blameable], [Sluggable], [Versionable]. Generated partial properties, SaveChanges hooks, and query filters. Zero boilerplate.

Part VII: Inheritance

One domain model, three persistence strategies. The Payment hierarchy configured as TPH, TPT, and TPC — same C# classes, one attribute change. Trade-off matrix: query performance, storage efficiency, migration complexity.

Part VIII: Customization and Escape Hatches

When the generator is not enough. PreConfigure/PostConfigure hooks, per-property overrides, partial repository extensions, IEntityListener, custom RepositoryBase hierarchy, DbContext options, multi-DbContext, the Specification pattern, and when to drop to raw Fluent API.

Part IX: The Full Domain

Everything assembled. All 14 entities with all attributes, relationships, behaviors, and inheritance. The complete Mermaid class diagram. Generated file inventory (42+ files). The DbContext, UnitOfWork, and DI wiring. End-to-end usage. Stats: 180 lines in, 2,800 lines out.

Part X: Comparison

Entity.Dsl vs hand-written Fluent API, EF Core conventions, Data Annotations, NHibernate, Dapper, and other source generators. Decision matrix: when Entity.Dsl shines, when it is overkill, and the honest cost of abstraction.


How to Read This Series

Architects evaluating the approach should read Parts I, III, IX, and X — the pitch, aggregate boundaries, the full domain, and the comparison.

Developers adopting Entity.Dsl should read Parts I and II for the fundamentals, then follow the domain build-up from III through IX.

Source Generator enthusiasts should read Part II standalone — it explains the incremental generator pipeline with real production code.

Anyone in a hurry should read Part I (the before/after) and Part IX (the assembled result).


Prerequisites

  • Familiarity with C# and .NET (examples use .NET 8+)
  • Basic understanding of Entity Framework Core (DbContext, Fluent API, migrations)
  • Familiarity with DDD concepts (aggregates, value objects, bounded contexts) is helpful but not required — the series explains them as they arise

The Domain: Online Marketplace

Throughout this series, we build a marketplace platform with these aggregate boundaries:

Aggregate Entities Key Relationships
Store Store, StoreSettings Composition (Store owns Settings)
Product Product, ProductVariant Composition (Product owns Variants), Aggregation to Store
Category Category Self-reference (Parent/Children tree)
Product-Category ProductCategory Association class (M:N with payload)
Customer Customer, Address Composition (Customer owns Address)
Order Order, OrderItem Composition (Order owns Items), Aggregation to Customer
Payment Payment, CreditCardPayment, BankTransferPayment, WalletPayment Inheritance (TPH)