From 9b8ec19644c4fe4a8864603fa63a2ac1450b86a7 Mon Sep 17 00:00:00 2001 From: AndriySvyryd Date: Wed, 6 Nov 2019 17:59:39 -0800 Subject: [PATCH] Add documentation for mapping two properties to the same column when using TPH Fixes #529 --- entity-framework/core/modeling/inheritance.md | 7 +- .../core/modeling/keyless-entity-types.md | 4 +- .../core/modeling/relational/inheritance.md | 65 +++++-------------- .../core/modeling/table-splitting.md | 2 +- .../FluentAPI/DefaultDiscriminator.cs | 29 +++++++++ .../FluentAPI/InheritanceTPHDiscriminator.cs | 2 +- .../FluentAPI/NonShadowDiscriminator.cs | 38 +++++++++++ .../Modeling/FluentAPI/SharedTPHColumns.cs | 37 +++++++++++ 8 files changed, 128 insertions(+), 56 deletions(-) create mode 100644 samples/core/Modeling/FluentAPI/DefaultDiscriminator.cs create mode 100644 samples/core/Modeling/FluentAPI/NonShadowDiscriminator.cs create mode 100644 samples/core/Modeling/FluentAPI/SharedTPHColumns.cs diff --git a/entity-framework/core/modeling/inheritance.md b/entity-framework/core/modeling/inheritance.md index c2ff6e0e1f..9c50d84499 100644 --- a/entity-framework/core/modeling/inheritance.md +++ b/entity-framework/core/modeling/inheritance.md @@ -1,8 +1,9 @@ --- title: Inheritance - EF Core -author: rowanmiller +description: How to configure entity type inheritance using Entity Framework Core +author: AndriySvyryd +ms.author: ansvyryd ms.date: 10/27/2016 -ms.assetid: 754be334-dd21-450e-9d22-2591e80012a2 uid: core/modeling/inheritance --- # Inheritance @@ -11,7 +12,7 @@ Inheritance in the EF model is used to control how inheritance in the entity cla ## Conventions -By convention, it is up to the database provider to determine how inheritance will be represented in the database. See [Inheritance (Relational Database)](relational/inheritance.md) for how this is handled with a relational database provider. +By default, it is up to the database provider to determine how inheritance will be represented in the database. See [Inheritance (Relational Database)](relational/inheritance.md) for how this is handled with a relational database provider. EF will only setup inheritance if two or more inherited types are explicitly included in the model. EF will not scan for base or derived types that were not otherwise included in the model. You can include types in the model by exposing a *DbSet\* for each type in the inheritance hierarchy. diff --git a/entity-framework/core/modeling/keyless-entity-types.md b/entity-framework/core/modeling/keyless-entity-types.md index 30e68751b8..4ed6ee9394 100644 --- a/entity-framework/core/modeling/keyless-entity-types.md +++ b/entity-framework/core/modeling/keyless-entity-types.md @@ -1,9 +1,9 @@ --- title: Keyless Entity Types - EF Core +description: How to configure keyless entity types using Entity Framework Core author: AndriySvyryd ms.author: ansvyryd -ms.date: 02/26/2018 -ms.assetid: 9F4450C5-1A3F-4BB6-AC19-9FAC64292AAD +ms.date: 9/13/2019 uid: core/modeling/keyless-entity-types --- # Keyless Entity Types diff --git a/entity-framework/core/modeling/relational/inheritance.md b/entity-framework/core/modeling/relational/inheritance.md index e9c96b590f..84e6f7bafd 100644 --- a/entity-framework/core/modeling/relational/inheritance.md +++ b/entity-framework/core/modeling/relational/inheritance.md @@ -1,8 +1,9 @@ --- title: Inheritance (Relational Database) - EF Core -author: rowanmiller -ms.date: 10/27/2016 -ms.assetid: 9a7c5488-aaf4-4b40-b1ff-f435ff30f6ec +description: How to configure entity type inheritance in a relational database using Entity Framework Core +author: AndriySvyryd +ms.author: ansvyryd +ms.date: 11/06/2019 uid: core/modeling/relational/inheritance --- # Inheritance (Relational Database) @@ -17,7 +18,7 @@ Inheritance in the EF model is used to control how inheritance in the entity cla ## Conventions -By convention, inheritance will be mapped using the table-per-hierarchy (TPH) pattern. TPH uses a single table to store the data for all types in the hierarchy. A discriminator column is used to identify which type each row represents. +By default, inheritance will be mapped using the table-per-hierarchy (TPH) pattern. TPH uses a single table to store the data for all types in the hierarchy. A discriminator column is used to identify which type each row represents. EF Core will only setup inheritance if two or more inherited types are explicitly included in the model (see [Inheritance](../inheritance.md) for more details). @@ -44,48 +45,14 @@ You can use the Fluent API to configure the name and type of the discriminator c In the examples above, the discriminator is created as a [shadow property](xref:core/modeling/shadow-properties) on the base entity of the hierarchy. Since it is a property in the model, it can be configured just like other properties. For example, to set the max length when the default, by-convention discriminator is being used: -```C# -modelBuilder.Entity() - .Property("Discriminator") - .HasMaxLength(200); -``` - -The discriminator can also be mapped to an actual CLR property in your entity. For example: - -```C# -class MyContext : DbContext -{ - public DbSet Blogs { get; set; } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - modelBuilder.Entity() - .HasDiscriminator("BlogType"); - } -} - -public class Blog -{ - public int BlogId { get; set; } - public string Url { get; set; } - public string BlogType { get; set; } -} - -public class RssBlog : Blog -{ - public string RssUrl { get; set; } -} -``` - -Combining these two things together it is possible to both map the discriminator to a real property and configure it: - -```C# -modelBuilder.Entity(b => -{ - b.HasDiscriminator("BlogType"); - - b.Property(e => e.BlogType) - .HasMaxLength(200) - .HasColumnName("blog_type"); -}); -``` +[!code-csharp[Main](../../../../samples/core/Modeling/FluentAPI/DefaultDiscriminator.cs#DiscriminatorConfiguration)] + +The discriminator can also be mapped to a .NET property in your entity and configure it. For example: + +[!code-csharp[Main](../../../../samples/core/Modeling/FluentAPI/NonShadowDiscriminator.cs#NonShadowDiscriminator)] + +## Shared columns + +When two sibling entity types have a property with the same name they will be mapped to two separate columns by default. But if they are compatible they can be mapped to the same column: + +[!code-csharp[Main](../../../../samples/core/Modeling/FluentAPI/SharedTPHColumns.cs#SharedTPHColumns)] \ No newline at end of file diff --git a/entity-framework/core/modeling/table-splitting.md b/entity-framework/core/modeling/table-splitting.md index ec0b21e0fe..6e76761dca 100644 --- a/entity-framework/core/modeling/table-splitting.md +++ b/entity-framework/core/modeling/table-splitting.md @@ -1,9 +1,9 @@ --- title: Table Splitting - EF Core +description: How to configure table splitting using Entity Framework Core author: AndriySvyryd ms.author: ansvyryd ms.date: 04/10/2019 -ms.assetid: 0EC2CCE1-BD55-45D8-9EA9-20634987F094 uid: core/modeling/table-splitting --- # Table Splitting diff --git a/samples/core/Modeling/FluentAPI/DefaultDiscriminator.cs b/samples/core/Modeling/FluentAPI/DefaultDiscriminator.cs new file mode 100644 index 0000000000..73bf729d61 --- /dev/null +++ b/samples/core/Modeling/FluentAPI/DefaultDiscriminator.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore; + +namespace EFModeling.FluentAPI.DefaultDiscriminator +{ + public class MyContext : DbContext + { + public DbSet Blogs { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + #region DiscriminatorConfiguration + modelBuilder.Entity() + .Property("Discriminator") + .HasMaxLength(200); + #endregion + } + } + + public class Blog + { + public int BlogId { get; set; } + public string Url { get; set; } + } + + public class RssBlog : Blog + { + public string RssUrl { get; set; } + } +} diff --git a/samples/core/Modeling/FluentAPI/InheritanceTPHDiscriminator.cs b/samples/core/Modeling/FluentAPI/InheritanceTPHDiscriminator.cs index 40dc75c9ca..cc3027a44d 100644 --- a/samples/core/Modeling/FluentAPI/InheritanceTPHDiscriminator.cs +++ b/samples/core/Modeling/FluentAPI/InheritanceTPHDiscriminator.cs @@ -3,7 +3,7 @@ namespace EFModeling.FluentAPI.InheritanceTphDiscriminator { #region Inheritance - class MyContext : DbContext + public class MyContext : DbContext { public DbSet Blogs { get; set; } diff --git a/samples/core/Modeling/FluentAPI/NonShadowDiscriminator.cs b/samples/core/Modeling/FluentAPI/NonShadowDiscriminator.cs new file mode 100644 index 0000000000..3a98854cc0 --- /dev/null +++ b/samples/core/Modeling/FluentAPI/NonShadowDiscriminator.cs @@ -0,0 +1,38 @@ +using Microsoft.EntityFrameworkCore; + +namespace EFModeling.FluentAPI.NonShadowDiscriminator +{ + #region NonShadowDiscriminator + public class MyContext : DbContext + { + public DbSet Blogs { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .Property("Discriminator") + .HasMaxLength(200); + + modelBuilder.Entity() + .HasDiscriminator(b => b.BlogType); + + modelBuilder.Entity() + .Property(e => e.BlogType) + .HasMaxLength(200) + .HasColumnName("blog_type"); + } + } + + public class Blog + { + public int BlogId { get; set; } + public string Url { get; set; } + public string BlogType { get; set; } + } + + public class RssBlog : Blog + { + public string RssUrl { get; set; } + } + #endregion +} diff --git a/samples/core/Modeling/FluentAPI/SharedTPHColumns.cs b/samples/core/Modeling/FluentAPI/SharedTPHColumns.cs new file mode 100644 index 0000000000..72e0244fc9 --- /dev/null +++ b/samples/core/Modeling/FluentAPI/SharedTPHColumns.cs @@ -0,0 +1,37 @@ +using Microsoft.EntityFrameworkCore; + +namespace EFModeling.FluentAPI.SharedTPHColumns +{ + #region SharedTPHColumns + public class MyContext : DbContext + { + public DbSet Blogs { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity() + .Property(b => b.Url) + .HasColumnName("Url"); + + modelBuilder.Entity() + .Property(b => b.Url) + .HasColumnName("Url"); + } + } + + public class BlogBase + { + public int BlogId { get; set; } + } + + public class Blog : BlogBase + { + public string Url { get; set; } + } + + public class RssBlog : BlogBase + { + public string Url { get; set; } + } + #endregion +}