From f8a3b7a367d4ab026d0a95d35b28f7834d9385bd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 02:54:47 +0000 Subject: [PATCH 1/4] Initial plan From 033b4eebeb36ac95c40bfebfb5940710e41902ec Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 02:58:45 +0000 Subject: [PATCH 2/4] Update DbFirst sample to use source generation instead of manual manifest creation Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com> --- .../JD.Domain.Samples.DbFirst/AssemblyInfo.cs | 3 + .../JD.Domain.Samples.DbFirst.csproj | 2 + samples/JD.Domain.Samples.DbFirst/Program.cs | 78 +++++++------------ 3 files changed, 35 insertions(+), 48 deletions(-) create mode 100644 samples/JD.Domain.Samples.DbFirst/AssemblyInfo.cs diff --git a/samples/JD.Domain.Samples.DbFirst/AssemblyInfo.cs b/samples/JD.Domain.Samples.DbFirst/AssemblyInfo.cs new file mode 100644 index 0000000..c2192a3 --- /dev/null +++ b/samples/JD.Domain.Samples.DbFirst/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using JD.Domain.ManifestGeneration; + +[assembly: GenerateManifest("BloggingDb", Version = "1.0.0", Namespace = "JD.Domain.Samples.DbFirst")] diff --git a/samples/JD.Domain.Samples.DbFirst/JD.Domain.Samples.DbFirst.csproj b/samples/JD.Domain.Samples.DbFirst/JD.Domain.Samples.DbFirst.csproj index 8eb9ef9..0229914 100644 --- a/samples/JD.Domain.Samples.DbFirst/JD.Domain.Samples.DbFirst.csproj +++ b/samples/JD.Domain.Samples.DbFirst/JD.Domain.Samples.DbFirst.csproj @@ -11,6 +11,8 @@ + + diff --git a/samples/JD.Domain.Samples.DbFirst/Program.cs b/samples/JD.Domain.Samples.DbFirst/Program.cs index 39c1098..b0d1739 100644 --- a/samples/JD.Domain.Samples.DbFirst/Program.cs +++ b/samples/JD.Domain.Samples.DbFirst/Program.cs @@ -1,4 +1,5 @@ -using JD.Domain.Abstractions; +using System.ComponentModel.DataAnnotations; +using JD.Domain.ManifestGeneration; using JD.Domain.Rules; using JD.Domain.Snapshot; @@ -6,18 +7,21 @@ namespace JD.Domain.Samples.DbFirst; /// /// Demonstrates database-first workflow: existing EF entities + JD rules as partials. +/// Manifests are now automatically generated from entity attributes - NO manual string writing! /// public static class Program { public static void Main() { - Console.WriteLine("=== JD.Domain Database-First Sample ===\n"); + Console.WriteLine("=== JD.Domain Database-First Sample (Automatic Manifest Generation) ===\n"); - // Step 1: Simulate loading manifest from scaffolded EF entities - Console.WriteLine("1. Loading manifest from existing EF entities..."); - var manifest = CreateManifestFromScaffoldedEntities(); - Console.WriteLine($" Loaded: {manifest.Name} v{manifest.Version}"); + // Step 1: Access auto-generated manifest from scaffolded EF entities + Console.WriteLine("1. Using auto-generated manifest from EF entities..."); + var manifest = BloggingDbManifest.GeneratedManifest; + Console.WriteLine($" Domain: {manifest.Name} v{manifest.Version}"); Console.WriteLine($" Entities: {manifest.Entities.Count}"); + Console.WriteLine($" Source: {manifest.Sources[0].Type}"); + Console.WriteLine($" NO MANUAL STRING WRITING REQUIRED!"); // Step 2: Add JD rules as partial classes (rules defined separately) Console.WriteLine("\n2. Defining rules for existing entities..."); @@ -63,63 +67,41 @@ public static void Main() } Console.WriteLine("\n=== Sample Complete ==="); - } - - /// - /// Simulates creating a manifest from EF Core scaffolded entities. - /// - private static DomainManifest CreateManifestFromScaffoldedEntities() - { - return new DomainManifest - { - Name = "BloggingDb", - Version = new Version(1, 0, 0), - Entities = - [ - new EntityManifest - { - Name = "Blog", - TypeName = "JD.Domain.Samples.DbFirst.Blog", - TableName = "Blogs", - Properties = - [ - new PropertyManifest { Name = "BlogId", TypeName = "System.Int32", IsRequired = true }, - new PropertyManifest { Name = "Url", TypeName = "System.String", IsRequired = true, MaxLength = 500 } - ], - KeyProperties = ["BlogId"] - }, - new EntityManifest - { - Name = "Post", - TypeName = "JD.Domain.Samples.DbFirst.Post", - TableName = "Posts", - Properties = - [ - new PropertyManifest { Name = "PostId", TypeName = "System.Int32", IsRequired = true }, - new PropertyManifest { Name = "Title", TypeName = "System.String", IsRequired = true, MaxLength = 200 }, - new PropertyManifest { Name = "Content", TypeName = "System.String", IsRequired = false }, - new PropertyManifest { Name = "BlogId", TypeName = "System.Int32", IsRequired = true } - ], - KeyProperties = ["PostId"] - } - ] - }; + Console.WriteLine("Manifest was generated automatically from entity attributes!"); } } -// These represent EF Core scaffolded entities +// These represent EF Core scaffolded entities with [DomainEntity] attributes added +// This demonstrates how you can add JD.Domain attributes to existing scaffolded entities +[DomainEntity(TableName = "Blogs")] public class Blog { + [Key] public int BlogId { get; set; } + + [Required] + [MaxLength(500)] public string Url { get; set; } = ""; + + [ExcludeFromManifest] public List Posts { get; set; } = new(); } +[DomainEntity(TableName = "Posts")] public class Post { + [Key] public int PostId { get; set; } + + [Required] + [MaxLength(200)] public string Title { get; set; } = ""; + public string? Content { get; set; } + + [Required] public int BlogId { get; set; } + + [ExcludeFromManifest] public Blog Blog { get; set; } = null!; } From 505a243be1bf7c734cb26e7f9987e716bbce5988 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 03:01:26 +0000 Subject: [PATCH 3/4] Update documentation to remove manual manifest creation examples Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com> --- docs/getting-started/choose-workflow.md | 91 +++++++++++++------------ 1 file changed, 49 insertions(+), 42 deletions(-) diff --git a/docs/getting-started/choose-workflow.md b/docs/getting-started/choose-workflow.md index ea5a336..063c790 100644 --- a/docs/getting-started/choose-workflow.md +++ b/docs/getting-started/choose-workflow.md @@ -152,31 +152,26 @@ Start with an existing database, scaffold EF Core entities, then add domain rule ### Example ```csharp -// 1. Entities scaffolded from database +// 1. Entities scaffolded from database with [DomainEntity] attributes added +[assembly: GenerateManifest("ECommerce", Version = "1.0.0")] + +[DomainEntity(TableName = "Customers")] public class Customer { + [Key] public int Id { get; set; } - public string Name { get; set; } - public string Email { get; set; } + + [Required] + [MaxLength(200)] + public string Name { get; set; } = ""; + + [Required] + [MaxLength(500)] + public string Email { get; set; } = ""; } -// 2. Create manifest from existing entities -var manifest = new DomainManifest -{ - Name = "ECommerce", - Entities = [ - new EntityManifest - { - Name = "Customer", - TypeName = "MyApp.Customer", - Properties = [ - new PropertyManifest { Name = "Id", TypeName = "System.Int32" }, - new PropertyManifest { Name = "Name", TypeName = "System.String" }, - new PropertyManifest { Name = "Email", TypeName = "System.String" } - ] - } - ] -}; +// 2. Manifest is automatically generated - NO manual creation needed! +var manifest = ECommerceManifest.GeneratedManifest; // 3. Add rules to scaffolded entities var rules = new RuleSetBuilder("Default") @@ -189,6 +184,8 @@ var rules = new RuleSetBuilder("Default") ```bash dotnet add package JD.Domain.Abstractions +dotnet add package JD.Domain.ManifestGeneration +dotnet add package JD.Domain.ManifestGeneration.Generator dotnet add package JD.Domain.Rules dotnet add package JD.Domain.Runtime dotnet add package JD.Domain.DomainModel.Generator # Optional @@ -208,7 +205,7 @@ dotnet add package JD.Domain.FluentValidation.Generator # Optional - ❌ Database remains source of truth (potential drift) - ❌ Less control over domain design - ❌ EF scaffolding can produce suboptimal models -- ❌ Requires manual manifest creation or tooling +- ❌ Requires adding attributes to scaffolded entities ### Next Steps @@ -251,33 +248,41 @@ Mix code-first domain definitions with database-first scaffolded entities, using ### Example ```csharp +// All entities use source generation - NO manual manifest creation! +[assembly: GenerateManifest("ECommerce", Version = "1.1.0")] + // Code-first entity -var codeFirstPart = Domain.Create("ECommerce") - .Entity(e => e - .Property(c => c.Id) - .Property(c => c.Name)) - .Build(); +[DomainEntity] +public class Customer +{ + [Key] + public int Id { get; set; } -// Database-first entity -var dbFirstPart = new DomainManifest + [Required] + [MaxLength(200)] + public string Name { get; set; } = ""; +} + +// Database-first entity (scaffolded with attributes added) +[DomainEntity(TableName = "Orders")] +public class Order { - Name = "ECommerce", - Entities = [ - new EntityManifest - { - Name = "Order", - TypeName = "MyApp.Order", - Properties = [ /* scaffolded properties */ ] - } - ] -}; - -// Merge manifests -var merged = MergeManifests(codeFirstPart, dbFirstPart); + [Key] + public int Id { get; set; } + + [Required] + public int CustomerId { get; set; } + + [Required] + public decimal Total { get; set; } +} + +// Access auto-generated manifest +var manifest = ECommerceManifest.GeneratedManifest; // Create snapshot var writer = new SnapshotWriter(); -var snapshot = writer.CreateSnapshot(merged); +var snapshot = writer.CreateSnapshot(manifest); // Later: compare versions var diff = diffEngine.Compare(snapshotV1, snapshotV2); @@ -408,6 +413,8 @@ dotnet add package JD.Domain.AspNetCore ```bash dotnet add package JD.Domain.Abstractions +dotnet add package JD.Domain.ManifestGeneration +dotnet add package JD.Domain.ManifestGeneration.Generator dotnet add package JD.Domain.Rules dotnet add package JD.Domain.Runtime ``` From 73a48c3893e35673e7e438c8e880f1e450d593f4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 03:04:27 +0000 Subject: [PATCH 4/4] Fix potential IndexOutOfRangeException in DbFirst sample Co-authored-by: JerrettDavis <2610199+JerrettDavis@users.noreply.github.com> --- samples/JD.Domain.Samples.DbFirst/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/JD.Domain.Samples.DbFirst/Program.cs b/samples/JD.Domain.Samples.DbFirst/Program.cs index b0d1739..9f9dda6 100644 --- a/samples/JD.Domain.Samples.DbFirst/Program.cs +++ b/samples/JD.Domain.Samples.DbFirst/Program.cs @@ -20,7 +20,7 @@ public static void Main() var manifest = BloggingDbManifest.GeneratedManifest; Console.WriteLine($" Domain: {manifest.Name} v{manifest.Version}"); Console.WriteLine($" Entities: {manifest.Entities.Count}"); - Console.WriteLine($" Source: {manifest.Sources[0].Type}"); + Console.WriteLine($" Source: {(manifest.Sources.Count > 0 ? manifest.Sources[0].Type : "Unknown")}"); Console.WriteLine($" NO MANUAL STRING WRITING REQUIRED!"); // Step 2: Add JD rules as partial classes (rules defined separately)