From 47547c8d9f59c03e16d887cac1f8162e5ff206fc Mon Sep 17 00:00:00 2001 From: kilfour Date: Tue, 12 Aug 2025 14:37:48 +0200 Subject: [PATCH 1/3] feat(schema): Doc for UniDirectionalOneToManyWithOneDbSet Moved File to own namespace. Removed Property Name as it's redundant. Removed sqlite test as there is no (apart from ddl dialect) noticable difference. Tried to put live code samples in the doc. Fixes #24. --- .../UniDirectionalOneToManyWithOneDbSet.cs | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 EntityFramework.Explained/Schema/Relationships/UniDirectionalOneToMany/UniDirectionalOneToManyWithOneDbSet.cs diff --git a/EntityFramework.Explained/Schema/Relationships/UniDirectionalOneToMany/UniDirectionalOneToManyWithOneDbSet.cs b/EntityFramework.Explained/Schema/Relationships/UniDirectionalOneToMany/UniDirectionalOneToManyWithOneDbSet.cs new file mode 100644 index 0000000..3d3c7bb --- /dev/null +++ b/EntityFramework.Explained/Schema/Relationships/UniDirectionalOneToMany/UniDirectionalOneToManyWithOneDbSet.cs @@ -0,0 +1,96 @@ +using EntityFramework.Explained._Tools.TestContexts; +using Microsoft.EntityFrameworkCore; +using QuickPulse.Explains; +using QuickPulse.Explains.Text; + +namespace EntityFramework.Explained.Schema.Relationships.UniDirectionalOneToMany; + +[DocFile] +[DocContent( +@"Because the entity used in the `DbSet` has a collection of another entity type, the latter are mapped as well. +EF infers and includes related entities in the schema even when only one side is explicitly registered in the `DbContext`. +")] +public class UniDirectionalOneToManyWithOneDbSet +{ + [DocExample] + public class Post + { + public int Id { get; set; } + public Blog Blog { get; set; } = default!; + } + + [DocExample] + public class Blog + { + public int Id { get; set; } + } + + [Fact] + [DocContent("When using the following simple model of *one* `Blog` containing *many* `Posts`:")] + [DocCodeExample(typeof(Blog))] + [DocCodeExample(typeof(Post))] + [DocContent("And then adding a `DbSet` to the `DbContext` EF generates the following ddl for Sql Server: \n")] + [DocContent("**Blog:**")] + [DocCodeExample(typeof(UniDirectionalOneToManyWithOneDbSet), nameof(ExpectedDdlScriptForBlog))] + [DocContent("**Post:**")] + [DocCodeExample(typeof(UniDirectionalOneToManyWithOneDbSet), nameof(ExpectedDdlScriptForPost))] + [DocContent("**Index:**")] + [DocCodeExample(typeof(UniDirectionalOneToManyWithOneDbSet), nameof(ExpectedDdlScriptForIndex))] + [DocContent("*Note:* No other mappings were added.")] + public void SqlServer() + { + using var context = new TestSqlServerContext(); + + var sql = context.Database.GenerateCreateScript(); + + var reader = LinesReader.FromText(sql); + + Assert.Equal(ExpectedDdlScriptForBlog(), reader.NextLines(4)); + + reader.Skip(3); + Assert.Equal(ExpectedDdlScriptForPost(), reader.NextLines(6)); + + reader.Skip(3); + Assert.Equal(ExpectedDdlScriptForIndex(), reader.NextLine()); + + reader.Skip(4); + Assert.True(reader.EndOfContent()); + } + + [DocSnippet] + [DocReplace("return", "")] + private string[] ExpectedDdlScriptForBlog() + { + return + [ + "CREATE TABLE [Blog] (", + " [Id] int NOT NULL IDENTITY,", + " CONSTRAINT [PK_Blog] PRIMARY KEY ([Id])", + ");" + ]; + } + + [DocSnippet] + [DocReplace("return", "")] + [DocReplace("Item", "Post")] + private string[] ExpectedDdlScriptForPost() + { + return + [ + "CREATE TABLE [Items] (", + " [Id] int NOT NULL IDENTITY,", + " [BlogId] int NOT NULL,", + " CONSTRAINT [PK_Items] PRIMARY KEY ([Id]),", + " CONSTRAINT [FK_Items_Blog_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blog] ([Id]) ON DELETE CASCADE", + ");" + ]; + } + + [DocSnippet] + [DocReplace("return", "")] + [DocReplace("Item", "Post")] + private string ExpectedDdlScriptForIndex() + { + return "CREATE INDEX [IX_Items_BlogId] ON [Items] ([BlogId]);"; + } +} \ No newline at end of file From e490f8bf5d4de3caf311ffe1daab433884bb6cce Mon Sep 17 00:00:00 2001 From: kilfour Date: Tue, 12 Aug 2025 14:58:06 +0200 Subject: [PATCH 2/3] forgot to delete this --- .../UniDirectionalOneToManyWithOneDbSet.cs | 88 ------------------- 1 file changed, 88 deletions(-) delete mode 100644 EntityFramework.Explained/Schema/Relationships/UniDirectionalOneToManyWithOneDbSet.cs diff --git a/EntityFramework.Explained/Schema/Relationships/UniDirectionalOneToManyWithOneDbSet.cs b/EntityFramework.Explained/Schema/Relationships/UniDirectionalOneToManyWithOneDbSet.cs deleted file mode 100644 index 858ff69..0000000 --- a/EntityFramework.Explained/Schema/Relationships/UniDirectionalOneToManyWithOneDbSet.cs +++ /dev/null @@ -1,88 +0,0 @@ -using EntityFramework.Explained._Tools.TestContexts; -using Microsoft.EntityFrameworkCore; -using QuickPulse.Explains; -using QuickPulse.Explains.Text; - -namespace EntityFramework.Explained.Schema.Relationships; - -[DocFile] -[DocContent("Because the entity used in the `DbSet` has a collection of another entity type, the latter are mapped as well.")] -public class UniDirectionalOneToManyWithOneDbSet -{ - public class Post - { - public int Id { get; set; } - public Blog Blog { get; set; } = default!; - } - - public class Blog - { - public int Id { get; set; } - public string Name { get; set; } = default!; - } - - [Fact] - [DocHeader("Sql Server")] - [DocContent("EF infers and includes related entities in the schema even when only one side is explicitly registered in the `DbContext`.")] - public void SqlServer() - { - using var context = new TestSqlServerContext(); - - var sql = context.Database.GenerateCreateScript(); - - var reader = LinesReader.FromText(sql); - Assert.Equal("CREATE TABLE [Blog] (", reader.NextLine()); - Assert.Equal(" [Id] int NOT NULL IDENTITY,", reader.NextLine()); - Assert.Equal(" [Name] nvarchar(max) NOT NULL,", reader.NextLine()); - Assert.Equal(" CONSTRAINT [PK_Blog] PRIMARY KEY ([Id])", reader.NextLine()); - Assert.Equal(");", reader.NextLine()); - Assert.Equal("GO", reader.NextLine()); - Assert.Equal("", reader.NextLine()); - Assert.Equal("", reader.NextLine()); - Assert.Equal("CREATE TABLE [Items] (", reader.NextLine()); - Assert.Equal(" [Id] int NOT NULL IDENTITY,", reader.NextLine()); - Assert.Equal(" [BlogId] int NOT NULL,", reader.NextLine()); - Assert.Equal(" CONSTRAINT [PK_Items] PRIMARY KEY ([Id]),", reader.NextLine()); - Assert.Equal(" CONSTRAINT [FK_Items_Blog_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blog] ([Id]) ON DELETE CASCADE", reader.NextLine()); - Assert.Equal(");", reader.NextLine()); - Assert.Equal("GO", reader.NextLine()); - Assert.Equal("", reader.NextLine()); - Assert.Equal("", reader.NextLine()); - Assert.Equal("CREATE INDEX [IX_Items_BlogId] ON [Items] ([BlogId]);", reader.NextLine()); - Assert.Equal("GO", reader.NextLine()); - Assert.Equal("", reader.NextLine()); - Assert.Equal("", reader.NextLine()); - Assert.Equal("", reader.NextLine()); - Assert.True(reader.EndOfContent()); - } - - [Fact] - [DocHeader("Sqlite")] - [DocContent("Same behavior as SqlServer, relationship discovery pulls in the `Blog` entity despite only registering `Post`")] - public void Sqlite() - { - using var context = new TestSqliteContext(); - - var sql = context.Database.GenerateCreateScript(); - - var reader = LinesReader.FromText(sql); - Assert.Equal("CREATE TABLE \"Blog\" (", reader.NextLine()); - Assert.Equal(" \"Id\" INTEGER NOT NULL CONSTRAINT \"PK_Blog\" PRIMARY KEY AUTOINCREMENT,", reader.NextLine()); - Assert.Equal(" \"Name\" TEXT NOT NULL", reader.NextLine()); - Assert.Equal(");", reader.NextLine()); - Assert.Equal("", reader.NextLine()); - Assert.Equal("", reader.NextLine()); - Assert.Equal("CREATE TABLE \"Items\" (", reader.NextLine()); - Assert.Equal(" \"Id\" INTEGER NOT NULL CONSTRAINT \"PK_Items\" PRIMARY KEY AUTOINCREMENT,", reader.NextLine()); - Assert.Equal(" \"BlogId\" INTEGER NOT NULL,", reader.NextLine()); - Assert.Equal(" CONSTRAINT \"FK_Items_Blog_BlogId\" FOREIGN KEY (\"BlogId\") REFERENCES \"Blog\" (\"Id\") ON DELETE CASCADE", reader.NextLine()); - Assert.Equal(");", reader.NextLine()); - Assert.Equal("", reader.NextLine()); - Assert.Equal("", reader.NextLine()); - Assert.Equal("CREATE INDEX \"IX_Items_BlogId\" ON \"Items\" (\"BlogId\");", reader.NextLine()); - Assert.Equal("", reader.NextLine()); - Assert.Equal("", reader.NextLine()); - Assert.Equal("", reader.NextLine()); - Assert.True(reader.EndOfContent()); - } -} \ No newline at end of file From 57e1120d13bf97e8aa3ace3ef38b67a2f3bf285c Mon Sep 17 00:00:00 2001 From: kilfour Date: Tue, 12 Aug 2025 16:57:14 +0200 Subject: [PATCH 3/3] commit to try to reindex pr's --- .../UniDirectionalOneToManyWithOneDbSet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EntityFramework.Explained/Schema/Relationships/UniDirectionalOneToMany/UniDirectionalOneToManyWithOneDbSet.cs b/EntityFramework.Explained/Schema/Relationships/UniDirectionalOneToMany/UniDirectionalOneToManyWithOneDbSet.cs index 3d3c7bb..69442b0 100644 --- a/EntityFramework.Explained/Schema/Relationships/UniDirectionalOneToMany/UniDirectionalOneToManyWithOneDbSet.cs +++ b/EntityFramework.Explained/Schema/Relationships/UniDirectionalOneToMany/UniDirectionalOneToManyWithOneDbSet.cs @@ -26,7 +26,7 @@ public class Blog } [Fact] - [DocContent("When using the following simple model of *one* `Blog` containing *many* `Posts`:")] + [DocContent("When using the following simple model of *one* `Blog` containing *many* `Posts`: ")] [DocCodeExample(typeof(Blog))] [DocCodeExample(typeof(Post))] [DocContent("And then adding a `DbSet` to the `DbContext` EF generates the following ddl for Sql Server: \n")]