Skip to content

Commit

Permalink
Document conventions and related model building concepts
Browse files Browse the repository at this point in the history
Fixes #1937
Fixes #779
Fixes #1016
Fixes #3756
  • Loading branch information
AndriySvyryd committed Nov 30, 2022
1 parent 0937bf8 commit 15fb84b
Show file tree
Hide file tree
Showing 19 changed files with 1,428 additions and 34 deletions.
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@
"navigations",
"overridable",
"parameterizable",
"parameterless",
"pluralizer",
"queryable",
"requiredness",
"resultset",
"resultsets",
"roundtrips",
"savepoint",
"savepoints",
"serializable",
"subquery"
"subquery",
"walkthrough"
],
"markdownlint.config": {
"MD028": false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ Table and column names are fixed up to better match the .NET naming conventions

## Fluent API or Data Annotations

Entity types are configured using the Fluent API by default. Specify `-DataAnnotations` (PMC) or `--data-annotations` (.NET Core CLI) to instead use data annotations when possible.
Entity types are configured using the [Fluent API](xref:core/modeling/index#use-fluent-api-to-configure-a-model) by default. Specify `-DataAnnotations` (PMC) or `--data-annotations` (.NET Core CLI) to instead use [Data Annotations](xref:core/modeling/index#use-data-annotations-to-configure-a-model) when possible.

For example, using the Fluent API will scaffold this:

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion entity-framework/core/modeling/backing-field.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ In the following sample, the `Url` property is configured to have `_url` as its

Note that backing fields are only discovered for properties that are included in the model. For more information on which properties are included in the model, see [Including & Excluding Properties](xref:core/modeling/entity-properties#included-and-excluded-properties).

You can also configure backing fields by using a Data Annotation (available in EFCore 5.0) or the Fluent API, e.g. if the field name doesn't correspond to the above conventions:
You can also configure backing fields by using a [Data Annotations](xref:core/modeling/index#use-data-annotations-to-configure-a-model) (available in EFCore 5.0) or the [Fluent API](xref:core/modeling/index#use-fluent-api-to-configure-a-model), e.g. if the field name doesn't correspond to the above conventions:

### [Data Annotations](#tab/data-annotations)

Expand Down
486 changes: 480 additions & 6 deletions entity-framework/core/modeling/bulk-configuration.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion entity-framework/core/modeling/entity-properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Each entity type in your model has a set of properties, which EF Core will read

## Included and excluded properties

By convention, all public properties with a getter and a setter will be included in the model.
By [convention](xref:core/modeling/index#built-in-conventions), all public properties with a getter and a setter will be included in the model.

Specific properties can be excluded as follows:

Expand Down
2 changes: 1 addition & 1 deletion entity-framework/core/modeling/entity-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ Note that setting the default schema will also affect other database objects, su

Entity types can be mapped to database views using the Fluent API.

> [!Note]
> [!NOTE]
> EF will assume that the referenced view already exists in the database, it will not create it automatically in a migration.
[!code-csharp[Main](../../../samples/core/Modeling/EntityTypes/FluentAPI/ViewNameAndSchema.cs?name=ViewNameAndSchema&highlight=1)]
Expand Down
109 changes: 99 additions & 10 deletions entity-framework/core/modeling/index.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
---
title: Creating and configuring a model - EF Core
description: Overview of creating and configuring a model with Entity Framework Core
title: Creating and Configuring a Model - EF Core
description: Overview of creating and configuring a Entity Framework Core model via Fluent API, Data Annotations and conventions.
author: AndriySvyryd
ms.date: 10/13/2020
ms.date: 11/11/2022
uid: core/modeling/index
---
# Creating and configuring a model
# Creating and Configuring a Model

Entity Framework Core uses a set of conventions to build a model based on the shape of your entity classes. You can specify additional configuration to supplement and/or override what was discovered by convention.
EF Core uses a metadata _model_ to describe how the application's entity types are mapped to the underlying database. This model is built using a set of [_conventions_](#built-in-conventions) - heuristics that look for common patterns. The model can then be customized using [mapping attributes (also known as _data annotations_)](#use-data-annotations-to-configure-a-model) and/or calls to the <xref:Microsoft.EntityFrameworkCore.ModelBuilder> methods [(also known as _fluent API_)](#use-fluent-api-to-configure-a-model) in <xref:Microsoft.EntityFrameworkCore.DbContext.OnModelCreating%2A>, both of which will override the configuration performed by conventions.

This article covers configuration that can be applied to a model targeting any data store and that which can be applied when targeting any relational database. Providers may also enable configuration that is specific to a particular data store. For documentation on provider specific configuration see the [Database Providers](xref:core/providers/index) section.
Most configuration can be applied to a model targeting any data store. Providers may also enable configuration that is specific to a particular data store and they can also ignore configuration that is not supported or not applicable. For documentation on provider-specific configuration see the [Database providers](xref:core/providers/index) section.

> [!TIP]
> You can view this article’s [sample](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples) on GitHub.
> You can view this article's [samples](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Modeling/) on GitHub.
## Use fluent API to configure a model

You can override the `OnModelCreating` method in your derived context and use the `ModelBuilder API` to configure your model. This is the most powerful method of configuration and allows configuration to be specified without modifying your entity classes. Fluent API configuration has the highest precedence and will override conventions and data annotations.
You can override the `OnModelCreating` method in your derived context and use the fluent API to configure your model. This is the most powerful method of configuration and allows configuration to be specified without modifying your entity classes. Fluent API configuration has the highest precedence and will override conventions and data annotations. The configuration is applied in the order the methods are called and if there are any conflicts the latest call will override previously specified configuration.

[!code-csharp[Main](../../../samples/core/Modeling/EntityProperties/FluentAPI/Required.cs?highlight=12-14)]

> [!TIP]
> To apply the same configuration to multiple objects in the model see [bulk configuration](xref:core/modeling/bulk-configuration).
### Grouping configuration

To reduce the size of the <xref:Microsoft.EntityFrameworkCore.DbContext.OnModelCreating%2A> method all configuration for an entity type can be extracted to a separate class implementing <xref:Microsoft.EntityFrameworkCore.IEntityTypeConfiguration%601>.
To reduce the size of the `OnModelCreating` method all configuration for an entity type can be extracted to a separate class implementing <xref:Microsoft.EntityFrameworkCore.IEntityTypeConfiguration%601>.

[!code-csharp[Main](../../../samples/core/Modeling/Misc/EntityTypeConfiguration.cs?Name=IEntityTypeConfiguration)]

Expand All @@ -39,6 +42,92 @@ It is possible to apply all configuration specified in types implementing `IEnti
## Use data annotations to configure a model

You can also apply attributes (known as Data Annotations) to your classes and properties. Data annotations will override conventions, but will be overridden by Fluent API configuration.
You can also apply certain attributes (known as _Data Annotations_) to your classes and properties. Data annotations will override conventions, but will be overridden by Fluent API configuration.

[!code-csharp[Main](../../../samples/core/Modeling/EntityProperties/DataAnnotations/Annotations.cs)]

## Built-in conventions

EF Core includes many model building conventions that are enabled by default. You can find all of them in the list of classes that implement the <xref:Microsoft.EntityFrameworkCore.Metadata.Conventions.IConvention> interface. However, that list doesn't include conventions introduced by third-party database providers and plugins.

Applications can remove or replace any of these conventions, as well as add new [custom conventions](xref:core/modeling/bulk-configuration#conventions) that apply configuration for patterns that are not recognized by EF out of the box.

> [!TIP]
> The code shown below comes from [ModelBuildingConventionsSample.cs](https://github.com/dotnet/EntityFramework.Docs/tree/main/samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs).
### Removing an existing convention

Sometimes one of the built-in conventions may not appropriate for your application, in which case it can be removed.

> [!TIP]
> If your model doesn't use mapping attributes (aka data annotations) for configuration, then all conventions with the name ending in `AttributeConvention` can be safely removed to speed up model building.
#### Example: Don't create indexes for foreign key columns

It usually makes sense to create indexes for foreign key (FK) columns, and hence there is a built-in convention for this: <xref:Microsoft.EntityFrameworkCore.Metadata.Conventions.ForeignKeyIndexConvention>. Looking at the model [debug view](#debug-view) for a `Post` entity type with relationships to `Blog` and `Author`, we can see two indexes are created--one for the `BlogId` FK, and the other for the `AuthorId` FK.

```text
EntityType: Post
Properties:
Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
AuthorId (no field, int?) Shadow FK Index
BlogId (no field, int) Shadow Required FK Index
Navigations:
Author (Author) ToPrincipal Author Inverse: Posts
Blog (Blog) ToPrincipal Blog Inverse: Posts
Keys:
Id PK
Foreign keys:
Post {'AuthorId'} -> Author {'Id'} ToDependent: Posts ToPrincipal: Author ClientSetNull
Post {'BlogId'} -> Blog {'Id'} ToDependent: Posts ToPrincipal: Blog Cascade
Indexes:
AuthorId
BlogId
```

However, indexes have overhead, and it may not always be appropriate to create them for all FK columns. To achieve this, the `ForeignKeyIndexConvention` can be removed when building the model:

```csharp
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Conventions.Remove(typeof(ForeignKeyIndexConvention));
}
```

Looking at the debug view of the model for `Post` now, we see that the indexes on FKs have not been created:

```text
EntityType: Post
Properties:
Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
AuthorId (no field, int?) Shadow FK
BlogId (no field, int) Shadow Required FK
Navigations:
Author (Author) ToPrincipal Author Inverse: Posts
Blog (Blog) ToPrincipal Blog Inverse: Posts
Keys:
Id PK
Foreign keys:
Post {'AuthorId'} -> Author {'Id'} ToDependent: Posts ToPrincipal: Author ClientSetNull
Post {'BlogId'} -> Blog {'Id'} ToDependent: Posts ToPrincipal: Blog Cascade
```

When desired, indexes can still be explicitly created for foreign key columns, either using the <xref:Microsoft.EntityFrameworkCore.IndexAttribute> or with configuration in `OnModelCreating`.

## Debug view

The model builder debug view can be accessed in the debugger of your IDE. For example, with Visual Studio:

![Accessing the model builder debug view from the Visual Studio debugger](_static/debug-view.png)

It can also be accessed directly from code, for example to send the debug view to the console:

```csharp
Console.WriteLine(context.Model.ToDebugString());
```

The debug view has a short form and a long form. The long form also includes all the annotations, which could be useful if you need to view relational or provider-specific metadata. The long view can be accessed from code as well:

```csharp
Console.WriteLine(context.Model.ToDebugString(MetadataDebugStringOptions.LongDefault));
```
2 changes: 1 addition & 1 deletion entity-framework/core/modeling/inheritance.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ The following sample exposes a DbSet for `Blog` and its subclass `RssBlog`. If `
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.
> If you don't rely on [conventions](xref:core/modeling/index#built-in-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.
## Table-per-hierarchy and discriminator configuration

Expand Down
2 changes: 1 addition & 1 deletion entity-framework/core/modeling/keyless-entity-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ In addition to regular entity types, an EF Core model can contain _keyless entit

## Defining Keyless entity types

Keyless entity types can be defined using either the Data Annotation or the Fluent API:
Keyless entity types can be defined as follows:

### [Data Annotations](#tab/data-annotations)

Expand Down
4 changes: 2 additions & 2 deletions entity-framework/core/modeling/relationships.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ You can use the Data Annotations to configure which property should be used as t

#### Shadow foreign key

You can use the string overload of `HasForeignKey(...)` to configure a shadow property as a foreign key (see [Shadow Properties](xref:core/modeling/shadow-properties) for more information). We recommend explicitly adding the shadow property to the model before using it as a foreign key (as shown below).
You can use the string overload of `HasForeignKey(...)` to configure a shadow property as a foreign key (see [Shadow Properties](xref:core/modeling/shadow-properties) for more information). The shadow property needs to exist before it can be used, you can explicitly declare it first as shown below.

[!code-csharp[Main](../../../samples/core/Modeling/Relationships/FluentAPI/ShadowForeignKey.cs?name=ShadowForeignKey&highlight=10,16)]

Expand Down Expand Up @@ -313,7 +313,7 @@ It is common to apply configuration to the join entity type. This action can be
> [!TIP]
> If there is no navigation on the other side `WithMany()` can be called without any arguments.
[Model seed data](xref:core/modeling/data-seeding) can be provided for the join entity type by using anonymous types. You can examine the model debug view to determine the property names created by convention.
[Model seed data](xref:core/modeling/data-seeding) can be provided for the join entity type by using anonymous types. You can examine the model [debug view](xref:core/modeling/index#debug-view) to determine the property names created by convention.

[!code-csharp[Main](../../../samples/core/Modeling/Relationships/FluentAPI/ManyToManyShared.cs?name=Seeding)]

Expand Down
6 changes: 3 additions & 3 deletions entity-framework/core/modeling/shadow-properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ Indexer properties are entity type properties, which are backed by an [indexer](

## Foreign key shadow properties

Shadow properties are most often used for foreign key properties, where the relationship between two entities is represented by a foreign key value in the database, but the relationship is managed on the entity types using navigation properties between the entity types. By convention, EF will introduce a shadow property when a relationship is discovered but no foreign key property is found in the dependent entity class.
Shadow properties are most often used for foreign key properties, where they are added to the model by convention when no foreign key property has been found by convention or configured explicitly. The relationship is represented by navigation properties, but in the database it is enforced by a foreign key constraint, and the value for the foreign key column is stored in the corresponding shadow property.

The property will be named `<navigation property name><principal key property name>` (the navigation on the dependent entity, which points to the principal entity, is used for the naming). If the principal key property name includes the name of the navigation property, then the name will just be `<principal key property name>`. If there is no navigation property on the dependent entity, then the principal type name is used in its place.
The property will be named `<navigation property name><principal key property name>` (the navigation on the dependent entity, which points to the principal entity, is used for the naming). If the principal key property name starts with the name of the navigation property, then the name will just be `<principal key property name>`. If there is no navigation property on the dependent entity, then the principal type name is used in its place.

For example, the following code listing will result in a `BlogId` shadow property being introduced to the `Post` entity:

[!code-csharp[Main](../../../samples/core/Modeling/ShadowAndIndexerProperties/ShadowForeignKey.cs?name=Conventions&highlight=21-23)]

## Configuring shadow properties

You can use the Fluent API to configure shadow properties. Once you have called the string overload of `Property`, you can chain any of the configuration calls you would for other properties. In the following sample, since `Blog` has no CLR property named `LastUpdated`, a shadow property is created:
You can use the [Fluent API](xref:core/modeling/index#use-fluent-api-to-configure-a-model) to configure shadow properties. Once you have called the string overload of <xref:Microsoft.EntityFrameworkCore.Metadata.Builders.EntityTypeBuilder.Property%60%601(System.String)>, you can chain any of the configuration calls you would for other properties. In the following sample, since `Blog` has no CLR property named `LastUpdated`, a shadow property is created:

[!code-csharp[Main](../../../samples/core/Modeling/ShadowAndIndexerProperties/ShadowProperty.cs?name=ShadowProperty&highlight=8)]

Expand Down
2 changes: 1 addition & 1 deletion entity-framework/core/modeling/table-splitting.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ Notice also that, if necessary, different column names can be specified for each

### Configuring the linking foreign key

The FK linking the mapped tables is targeting the same properties on which it is declared. Normally it wouldn't be created in the database, as it would be redundant. But there's an exception for when the entity type is mapped to more than one table. To change its facets you can use the normal [relationship Fluent API](xref:core/modeling/relationships#foreign-key):
The FK linking the mapped tables is targeting the same properties on which it is declared. Normally it wouldn't be created in the database, as it would be redundant. But there's an exception for when the entity type is mapped to more than one table. To change its facets you can use the [relationship configuration Fluent API](xref:core/modeling/relationships#foreign-key):

<!--
modelBuilder.Entity<Customer>()
Expand Down
2 changes: 1 addition & 1 deletion entity-framework/core/providers/sql-server/misc.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ You can let EF Core know that the target table has a trigger; doing so will reve

Note that doing this doesn't actually make EF Core create or manage the trigger in any way - it currently only informs EF Core that triggers are present on the table. As a result, any trigger name can be used, and this can also be used if an unsupported computed column is in use (regardless of triggers).

If most or all of your tables have triggers, you can opt out of using the newer, efficient technique for all your model's tables by using the following model building convention:
If most or all of your tables have triggers, you can opt out of using the newer, efficient technique for all your model's tables by using the following [model building convention](xref:core/modeling/bulk-configuration#conventions):

[!code-csharp[Main](../../../../samples/core/SqlServer/Misc/TriggersContext.cs?name=BlankTriggerAddingConvention)]

Expand Down
Loading

0 comments on commit 15fb84b

Please sign in to comment.