Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge relational/inheritance into inheritance page #1992

Merged
merged 1 commit into from
Dec 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .openpublishing.redirection.json
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,11 @@
"source_path": "entity-framework/core/modeling/relational/computed-columns.md",
"redirect_url": "/ef/core/modeling/generated-properties#computed-columns",
"redirect_document_id": false
},
{
"source_path": "entity-framework/core/modeling/relational/inheritance.md",
"redirect_url": "/ef/core/modeling/inheritance",
"redirect_document_id": false
}
]
}
49 changes: 35 additions & 14 deletions entity-framework/core/modeling/inheritance.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,49 @@ uid: core/modeling/inheritance
---
# Inheritance

Inheritance in the EF model is used to control how inheritance in the entity classes is represented in the database.
EF can map a .NET type hierarchy to a database. This allows you to write your .NET entities in code as usual, using base and derived types, and have EF seamlessly create the appropriate database schema, issue queries, etc. The actual details of how a type hierarchy is mapped are provider-dependent; this page describes inheritance support in the context of a relational database.

## Conventions
At the moment, EF Core only supports the table-per-hierarchy (TPH) pattern. TPH uses a single table to store the data for all types in the hierarchy, and a discriminator column is used to identify which type each row represents.

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.
> [!NOTE]
> The table-per-type (TPT) and table-per-concrete-type (TPC), which are supported by EF6, are not yet supported by EF Core. TPT is a major feature planned for EF Core 5.0.

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\<TEntity>* for each type in the inheritance hierarchy.
## Entity type hierarchy mapping

[!code-csharp[Main](../../../samples/core/Modeling/Conventions/InheritanceDbSets.cs?highlight=3-4&name=Model)]
By convention, EF will only set up inheritance if two or more inherited types are explicitly included in the model. EF will not automatically scan for base or derived types that are not otherwise included in the model.

If you don't want to expose a *DbSet\<TEntity>* for one or more entities in the hierarchy, you can use the Fluent API to ensure they are included in the model.
And if you don't rely on conventions, you can specify the base type explicitly using `HasBaseType`.
You can include types in the model by exposing a DbSet for each type in the inheritance hierarchy:

[!code-csharp[Main](../../../samples/core/Modeling/Conventions/InheritanceModelBuilder.cs?highlight=7&name=Context)]
[!code-csharp[Main](../../../samples/core/Modeling/Conventions/InheritanceDbSets.cs?name=InheritanceDbSets&highlight=3-4)]

> [!NOTE]
> You can use `.HasBaseType((Type)null)` to remove an entity type from the hierarchy.
This model be mapped to the following database schema (note the implicitly-created *Discriminator* column, which identifies which type of *Blog* is stored in each row):

![image](_static/inheritance-tph-data.png)

>[!NOTE]
> Database columns are automatically made nullable as necessary when using TPH mapping. For example, the *RssUrl* column is nullable because regular *Blog* instances do not have that property.
roji marked this conversation as resolved.
Show resolved Hide resolved

If you don't want to expose a DbSet for one or more entities in the hierarchy, you can also use the Fluent API to ensure they are included in the model.

> [!TIP]
> If you don't rely on conventions, you can specify the base type explicitly using `HasBaseType`. You can also use `.HasBaseType((Type)null)` to remove an entity type from the hierarchy.

## Discriminator configuration

You can configure the name and type of the discriminator column and the values that are used to identify each type in the hierarchy:

[!code-csharp[Main](../../../samples/core/Modeling/FluentAPI/DiscriminatorConfiguration.cs?name=DiscriminatorConfiguration&highlight=4-6)]

In the examples above, EF added the discriminator implicitly as a [shadow property](xref:core/modeling/shadow-properties) on the base entity of the hierarchy. This property can be configured like any other:

[!code-csharp[Main](../../../samples/core/Modeling/FluentAPI/DiscriminatorPropertyConfiguration.cs?name=DiscriminatorPropertyConfiguration&highlight=4-5)]

Finally, the discriminator can also be mapped to a regular .NET property in your entity:

## Data Annotations
[!code-csharp[Main](../../../samples/core/Modeling/FluentAPI/NonShadowDiscriminator.cs?name=NonShadowDiscriminator&highlight=4)]

You cannot use Data Annotations to configure inheritance.
## Shared columns

## Fluent API
By default, when two sibling entity types in the hierarchy have a property with the same name, they will be mapped to two separate columns. However, if their type is identical they can be mapped to the same database column:

The Fluent API for inheritance depends on the database provider you are using. See [Inheritance (Relational Database)](relational/inheritance.md) for the configuration you can perform for a relational database provider.
[!code-csharp[Main](../../../samples/core/Modeling/FluentAPI/SharedTPHColumns.cs?name=SharedTPHColumns&highlight=9,13)]
58 changes: 0 additions & 58 deletions entity-framework/core/modeling/relational/inheritance.md

This file was deleted.

2 changes: 0 additions & 2 deletions entity-framework/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,6 @@
items:
- name: Overview
href: core/modeling/relational/index.md
- name: Inheritance (Relational Database)
href: core/modeling/relational/inheritance.md
- name: Managing Database Schemas
items:
- name: Overview
Expand Down
2 changes: 1 addition & 1 deletion samples/core/Modeling/Conventions/InheritanceDbSets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace EFModeling.Conventions.InheritanceDbSets
{

#region Model
#region InheritanceDbSets
class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
Expand Down
27 changes: 0 additions & 27 deletions samples/core/Modeling/Conventions/InheritanceModelBuilder.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
using Microsoft.EntityFrameworkCore;

namespace EFModeling.FluentAPI.InheritanceTphDiscriminator
namespace EFModeling.FluentAPI.DiscriminatorConfiguration
{
#region Inheritance
public class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }

#region DiscriminatorConfiguration
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasDiscriminator<string>("blog_type")
.HasValue<Blog>("blog_base")
.HasValue<RssBlog>("blog_rss");
}
#endregion
}

public class Blog
Expand All @@ -26,5 +27,4 @@ public class RssBlog : Blog
{
public string RssUrl { get; set; }
}
#endregion
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
using Microsoft.EntityFrameworkCore;

namespace EFModeling.FluentAPI.DefaultDiscriminator
namespace EFModeling.FluentAPI.DiscriminatorPropertyConfiguration
{
public class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }

#region DiscriminatorPropertyConfiguration
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
#region DiscriminatorConfiguration
modelBuilder.Entity<Blog>()
.Property("Discriminator")
.HasMaxLength(200);
#endregion
}
#endregion
}

public class Blog
Expand Down
8 changes: 2 additions & 6 deletions samples/core/Modeling/FluentAPI/NonShadowDiscriminator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@

namespace EFModeling.FluentAPI.NonShadowDiscriminator
{
#region NonShadowDiscriminator
public class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }

#region NonShadowDiscriminator
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property("Discriminator")
.HasMaxLength(200);

modelBuilder.Entity<Blog>()
.HasDiscriminator(b => b.BlogType);

Expand All @@ -21,6 +17,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
.HasMaxLength(200)
.HasColumnName("blog_type");
}
#endregion
}

public class Blog
Expand All @@ -34,5 +31,4 @@ public class RssBlog : Blog
{
public string RssUrl { get; set; }
}
#endregion
}