From 15fb84b1f3c384213224942cbc55769740502244 Mon Sep 17 00:00:00 2001 From: AndriySvyryd Date: Tue, 8 Nov 2022 10:51:16 -0800 Subject: [PATCH] Document conventions and related model building concepts Fixes #1937 Fixes #779 Fixes #1016 Fixes #3756 --- .vscode/settings.json | 5 +- .../managing-schemas/scaffolding/index.md | 2 +- .../core/modeling/_static/debug-view.png | Bin 0 -> 75875 bytes .../core/modeling/backing-field.md | 2 +- .../core/modeling/bulk-configuration.md | 486 +++++++++++++++++- .../core/modeling/entity-properties.md | 2 +- .../core/modeling/entity-types.md | 2 +- entity-framework/core/modeling/index.md | 109 +++- entity-framework/core/modeling/inheritance.md | 2 +- .../core/modeling/keyless-entity-types.md | 2 +- .../core/modeling/relationships.md | 4 +- .../core/modeling/shadow-properties.md | 6 +- .../core/modeling/table-splitting.md | 2 +- .../core/providers/sql-server/misc.md | 2 +- .../core/what-is-new/ef-core-7.0/whatsnew.md | 2 +- .../BulkConfiguration/BlogsContext.cs | 425 +++++++++++++++ .../BulkConfiguration.csproj | 1 + .../ModelBuildingConventionsSample.cs | 396 ++++++++++++++ .../Modeling/BulkConfiguration/Program.cs | 12 +- 19 files changed, 1428 insertions(+), 34 deletions(-) create mode 100644 entity-framework/core/modeling/_static/debug-view.png create mode 100644 samples/core/Modeling/BulkConfiguration/BlogsContext.cs create mode 100644 samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs diff --git a/.vscode/settings.json b/.vscode/settings.json index f0c752e0c6..e582f44ff1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -18,15 +18,18 @@ "navigations", "overridable", "parameterizable", + "parameterless", "pluralizer", "queryable", + "requiredness", "resultset", "resultsets", "roundtrips", "savepoint", "savepoints", "serializable", - "subquery" + "subquery", + "walkthrough" ], "markdownlint.config": { "MD028": false, diff --git a/entity-framework/core/managing-schemas/scaffolding/index.md b/entity-framework/core/managing-schemas/scaffolding/index.md index dd5dd531c8..f0a619f566 100644 --- a/entity-framework/core/managing-schemas/scaffolding/index.md +++ b/entity-framework/core/managing-schemas/scaffolding/index.md @@ -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: diff --git a/entity-framework/core/modeling/_static/debug-view.png b/entity-framework/core/modeling/_static/debug-view.png new file mode 100644 index 0000000000000000000000000000000000000000..c0ecc80b8073f89501bb2a497923bad794524f80 GIT binary patch literal 75875 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

ODsrKCme#4zVq@xq9^}3x11bp;B4gGYSem$ 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 SPbm>fDiuXFg}l3uU;Z1vcV;mF literal 0 HcmV?d00001 diff --git a/entity-framework/core/modeling/backing-field.md b/entity-framework/core/modeling/backing-field.md index 683ff9fdd8..ee44442273 100644 --- a/entity-framework/core/modeling/backing-field.md +++ b/entity-framework/core/modeling/backing-field.md @@ -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) diff --git a/entity-framework/core/modeling/bulk-configuration.md b/entity-framework/core/modeling/bulk-configuration.md index cf4c4fca1e..c8c33f7260 100644 --- a/entity-framework/core/modeling/bulk-configuration.md +++ b/entity-framework/core/modeling/bulk-configuration.md @@ -1,8 +1,8 @@ --- title: Model Bulk Configuration - EF Core -description: How to apply bulk configuration during model building in Entity Framework Core +description: How to apply bulk configuration during model building in Entity Framework Core via Metadata API, conventions or pre-convention configuration. author: AndriySvyryd -ms.date: 11/05/2021 +ms.date: 11/11/2022 uid: core/modeling/bulk-configuration --- # Model bulk configuration @@ -27,13 +27,16 @@ Properties of this type are not discovered by default as the current EF provider ### Drawbacks of the Metadata API -- Unlike Fluent API, every modification to the model needs to be done explicitly. For example, if some of the `Currency` properties were configured as navigations by a convention then you need to first remove the navigation referencing the CLR property before adding an entity type property for it. [#9117](https://github.com/dotnet/efcore/issues/9117) will improve this. +- Unlike [Fluent API](xref:core/modeling/index#use-fluent-api-to-configure-a-model), every modification to the model needs to be done explicitly. For example, if some of the `Currency` properties were configured as navigations by a convention then you need to first remove the navigation referencing the CLR property before adding an entity type property for it. [#9117](https://github.com/dotnet/efcore/issues/9117) will improve this. - The conventions run after each change. If you remove a navigation discovered by a convention then the convention will run again and could add it back. To prevent this from happening you would need to either delay the conventions until after the property is added by calling and later disposing the returned object or to mark the CLR property as ignored using . - Entity types might be added after this iteration happens and the configuration won't be applied to them. This can usually be prevented by placing this code at the end of `OnModelCreating`, but if you have two interdependent sets of configurations there might not be an order that will allow them to be applied consistently. ## Pre-convention configuration -EF Core 6.0 allows the mapping configuration to be specified once for a given CLR type; that configuration is then applied to all properties of that type in the model as they are discovered. This is called "pre-convention model configuration", since it configures aspects of the model that are then used by the model building conventions. Such configuration is applied by overriding on the type derived from . +> [!NOTE] +> Pre-convention configuration was introduced in EF Core 6.0. + +EF Core allows the mapping configuration to be specified once for a given CLR type; that configuration is then applied to all properties of that type in the model as they are discovered. This is called "pre-convention model configuration", since it configures aspects of the model before the model building conventions are allowed to run. Such configuration is applied by overriding on the type derived from . This example shows how configure all properties of type `Currency` to have a value converter: @@ -52,8 +55,8 @@ And this example shows how to configure some facets on all properties of type `s > 4. Non-nullable value type > 5. Exact type -> [!NOTE] -> Data annotations do not override pre-convention configuration. +> [!IMPORTANT] +> Pre-convention configuration is equivalent to explicit configuration that is applied as soon as a matching object is added to the model. It will override all conventions and Data Annotations. For example, with the above configuration all string foreign key properties will be created as non-unicode with `MaxLength` of 1024, even when this doesn't match the principal key. ### Ignoring types @@ -72,3 +75,474 @@ Generally, EF is able to translate queries with constants of a type that is not - Many aspects cannot be configured with this approach. [#6787](https://github.com/dotnet/efcore/issues/6787) will expand this to more types. - Currently the configuration is only determined by the CLR type. [#20418](https://github.com/dotnet/efcore/issues/20418) would allow custom predicates. - This configuration is performed before a model is created. If there are any conflicts that arise when applying it, the exception stack trace will not contain the `ConfigureConventions` method, so it might be harder to find the cause. + +## Conventions + +> [!NOTE] +> Custom model building conventions were introduced in EF Core 7.0. + +EF Core model building conventions are classes that contain logic that is triggered based on changes being made to the model as it is being built. This keeps the model up-to-date as explicit configuration is made, mapping attributes are applied, and other conventions run. To participate in this, every convention implements one or more interfaces which determine when the corresponding method will be triggered. For example, a convention that implements will be triggered whenever a new entity type is added to the model. Likewise, a convention that implements both and will be triggered whenever either a key or a foreign key is added to the model. + +Model building conventions are a powerful way to control the model configuration, but can be complex and hard to get right. In many cases, the [pre-convention model configuration](#pre-convention-configuration) can be used instead to easily specify common configuration for properties and types. + +### Adding a new convention + +#### Example: Constrain length of discriminator properties + +The [table-per-hierarchy inheritance mapping strategy](xref:core/modeling/inheritance) requires a discriminator column to specify which type is represented in any given row. By default, EF uses an unbounded string column for the discriminator, which ensures that it will work for any discriminator length. However, constraining the maximum length of discriminator strings can make for more efficient storage and queries. Let's create a new convention that will do that. + +EF Core model building conventions are triggered based on changes being made to the model as it is being built. This keeps the model up-to-date as explicit configuration is made, mapping attributes are applied, and other conventions run. To participate in this, every convention implements one or more interfaces which determine when the convention will be triggered. For example, a convention that implements will be triggered whenever a new entity type is added to the model. Likewise, a convention that implements both and will be triggered whenever either a key or a foreign key is added to the model. + +Knowing which interfaces to implement can be tricky, since configuration made to the model at one point may be changed or removed at a later point. For example, a key may be created by convention, but then later replaced when a different key is configured explicitly. + +Let's make this a bit more concrete by making a first attempt at implementing the discriminator-length convention: + + +[!code-csharp[DiscriminatorLengthConvention1](../../../samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs?name=DiscriminatorLengthConvention1)] + +This convention implements , which means it will be triggered whenever the mapped inheritance hierarchy for an entity type is changed. The convention then finds and configures the string discriminator property for the hierarchy. + +This convention is then used by calling in `ConfigureConventions`: + +```csharp +protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) +{ + configurationBuilder.Conventions.Add(_ => new DiscriminatorLengthConvention1()); +} +``` + +> [!NOTE] +> Rather than adding an instance of the convention directly, the `Add` method accepts a factory for creating instances of the convention. This allows the convention to use dependencies from the EF Core internal service provider. Since this convention has no dependencies, the service provider parameter is named `_`, indicating that it is never used. + +Building the model and looking at the `Post` entity type shows that this has worked - the discriminator property is now configured to with a maximum length of 24: + +```text + Discriminator (no field, string) Shadow Required AfterSave:Throw MaxLength(24) +``` + +But what happens if we now explicitly configure a different discriminator property? For example: + +```csharp +modelBuilder.Entity() + .HasDiscriminator("PostTypeDiscriminator") + .HasValue("Post") + .HasValue("Featured"); +``` + +Looking at the [debug view](xref:core/modeling/index#debug-view) of the model, we find that the discriminator length is no longer configured. + +```text + PostTypeDiscriminator (no field, string) Shadow Required AfterSave:Throw +``` + +This is because the discriminator property that we configured in our convention was later removed when the custom discriminator was added. We could attempt to fix this by implementing another interface on our convention to react to the discriminator changes, but figuring out which interface to implement is not easy. + +Fortunately, there is an easier approach. A lot of the time, it doesn't matter what the model looks like while it is being built, as long as the final model is correct. In addition, the configuration we want to apply often does not need to trigger other conventions to react. Therefore, our convention can implement . _Model finalizing conventions_ run after all other model building is complete, and so have access to the near-final state of the model. This is opposed to _interactive conventions_ that react to each model change and make sure that the model is up-to-date at any point of the `OnModelCreating` method execution. A model finalizing convention will typically iterate over the entire model configuring model elements as it goes. So, in this case, we will find every discriminator in the model and configure it: + + +[!code-csharp[DiscriminatorLengthConvention2](../../../samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs?name=DiscriminatorLengthConvention2)] + +After building the model with this new convention, we find that the discriminator length is now configured correctly even though it has been customized: + +```text +PostTypeDiscriminator (no field, string) Shadow Required AfterSave:Throw MaxLength(24) +``` + +We can go one step further and configure the max length to be the length of the longest discriminator value: + + +[!code-csharp[DiscriminatorLengthConvention3](../../../samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs?name=DiscriminatorLengthConvention3)] + +Now the discriminator column max length is 8, which is the length of "Featured", the longest discriminator value in use. + +```text +PostTypeDiscriminator (no field, string) Shadow Required AfterSave:Throw MaxLength(8) +``` + +#### Example: Default length for all string properties + +Let's look at another example where a finalizing convention can be used - setting a default maximum length for _any_ string property. The convention looks quite similar to the previous example: + + +[!code-csharp[MaxStringLengthConvention](../../../samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs?name=MaxStringLengthConvention)] + +This convention is pretty simple. It finds every string property in the model and sets its max length to 512. Looking in the debug view at the properties for `Post`, we see that all the string properties now have a max length of 512. + +```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 + Content (string) Required MaxLength(512) + Discriminator (no field, string) Shadow Required AfterSave:Throw MaxLength(512) + PublishedOn (DateTime) Required + Title (string) Required MaxLength(512) +``` + +> [!NOTE] +> The same can be accomplished by pre-convention configuration, but using a convention allows to further filter applicable properties and for [Data Annotations to override the configuration](xref:core/modeling/index). + +Finally, before we leave this example, what happens if we use both the `MaxStringLengthConvention` and `DiscriminatorLengthConvention3` at the same time? The answer is that it depends which order they are added, since model finalizing conventions run in the order they are added. So if `MaxStringLengthConvention` is added last, then it will run last, and it will set the max length of the discriminator property to 512. Therefore, in this case, it is better to add `DiscriminatorLengthConvention3` last so that it can override the default max length for just discriminator properties, while leaving all other string properties as 512. + +### Replacing an existing convention + +Sometimes rather than removing an existing convention completely we instead want to replace it with a convention that does basically the same thing, but with changed behavior. This is useful because the existing convention will already implement the interfaces it needs to be triggered appropriately. + +#### Example: Opt-in property mapping + +EF Core maps all public read-write properties by convention. This might not be appropriate for the way your entity types are defined. To change this, we can replace the with our own implementation that doesn't map any property unless it is explicitly mapped in `OnModelCreating` or marked with a new attribute called `Persist`: + + +[!code-csharp[PersistAttribute](../../../samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs?name=PersistAttribute)] + +Here is the new convention: + + +[!code-csharp[AttributeBasedPropertyDiscoveryConvention](../../../samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs?name=AttributeBasedPropertyDiscoveryConvention)] + +> [!TIP] +> When replacing a built-in convention, the new convention implementation should inherit from the existing convention class. Note that some conventions have relational or provider-specific implementations, in which case the new convention implementation should inherit from the most specific existing convention class for the database provider in use. + +The convention is then registered using the method in `ConfigureConventions`: + + +[!code-csharp[ReplaceConvention](../../../samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs?name=ReplaceConvention)] + +> [!TIP] +> This is a case where the existing convention has dependencies, represented by the `ProviderConventionSetBuilderDependencies` dependency object. These are obtained from the internal service provider using `GetRequiredService` and passed to the convention constructor. + +Notice that this convention allows fields to be mapped (in addition to properties) so long as they are marked with `[Persist]`. This means we can use private fields as hidden keys in the model. + +For example, consider the following entity types: + + +[!code-csharp[LaundryBasket](../../../samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs?name=LaundryBasket)] + +The model built from these entity types is: + +```text +Model: + EntityType: Garment + Properties: + _id (_id, int) Required PK AfterSave:Throw ValueGenerated.OnAdd + Basket_id (no field, int?) Shadow FK Index + Color (string) Required + Name (string) Required + TenantId (int) Required + Navigations: + Basket (LaundryBasket) ToPrincipal LaundryBasket Inverse: Garments + Keys: + _id PK + Foreign keys: + Garment {'Basket_id'} -> LaundryBasket {'_id'} ToDependent: Garments ToPrincipal: Basket ClientSetNull + Indexes: + Basket_id + EntityType: LaundryBasket + Properties: + _id (_id, int) Required PK AfterSave:Throw ValueGenerated.OnAdd + TenantId (int) Required + Navigations: + Garments (List) Collection ToDependent Garment Inverse: Basket + Keys: + _id PK +``` + +Normally, `IsClean` would have been mapped, but since it is not marked with `[Persist]`, it is now treated as an un-mapped property. + +> [!TIP] +> This convention could not be implemented as a model finalizing convention because there are existing model finalizing conventions that need to run after the property is mapped to further configure it. + +### Conventions implementation considerations + +EF Core keeps track of how every piece of configuration was made. This is represented by the enum. The different kinds of configuration are: + +- `Explicit`: The model element was explicitly configured in `OnModelCreating` +- `DataAnnotation`: The model element was configured using a mapping attribute (aka data annotation) on the CLR type +- `Convention`: The model element was configured by a model building convention + +Conventions should never override configuration marked as `DataAnnotation` or `Explicit`. This is achieved by using a _convention builder_, for example, the , which is obtained from the property. For example: + +```csharp +property.Builder.HasMaxLength(512); +``` + +Calling `HasMaxLength` on the convention builder will only set the max length _if it was not already configured by a mapping attribute or in `OnModelCreating`_. + +Builder methods like this also have a second parameter: `fromDataAnnotation`. Set this to `true` if the convention is making the configuration on behalf of a mapping attribute. For example: + +```csharp +property.Builder.HasMaxLength(512, fromDataAnnotation: true); +``` + +This sets the `ConfigurationSource` to `DataAnnotation`, which means that the value can now be overridden by explicit mapping on `OnModelCreating`, but not by non-mapping attribute conventions. + +If the current configuration can't be overridden then the method will return `null`, this needs to be accounted for if you need to perform further configuration: + +```csharp +property.Builder.HasMaxLength(512)?.IsUnicode(false); +``` + +Notice that if the unicode configuration can't be overridden the max length will still be set. In case when you need to configure the facets only when both calls succeed then you can preemptively check this by calling and : + + +[!code-csharp[MaxStringLengthNonUnicodeConvention](../../../samples/core/Modeling/BulkConfiguration/ModelBuildingConventionsSample.cs?name=MaxStringLengthNonUnicodeConvention)] + +Here we can be sure that the call to `HasMaxLength` will not return `null`. It is still recommended to use the builder instance returned from `HasMaxLength` as it might be different from `propertyBuilder`. + +> [!NOTE] +> Other conventions are not triggered immediately after a convention makes a change, they are delayed until all conventions have finished processing the current change. + +### IConventionContext + +All convention methods also have an parameter. It provides methods that could be useful in some specific cases. + +#### Example: NotMappedAttribute convention + +This convention looks for on a type that is added to the model and tries to remove that entity type from the model. But if the entity type is removed from the model then any other conventions that implement `ProcessEntityTypeAdded` no longer need to be run. This can be accomplished by calling : + +```csharp +public virtual void ProcessEntityTypeAdded( + IConventionEntityTypeBuilder entityTypeBuilder, + IConventionContext context) +{ + var type = entityTypeBuilder.Metadata.ClrType; + if (!Attribute.IsDefined(type, typeof(NotMappedAttribute), inherit: true)) + { + return; + } + + if (entityTypeBuilder.ModelBuilder.Ignore(entityTypeBuilder.Metadata.Name, fromDataAnnotation: true) != null) + { + context.StopProcessing(); + } +} +``` + +### IConventionModel + +Every builder object passed to the convention exposes a property that provides a low-level access to the objects that comprise the model. In particular, there are methods that allow you to iterate over specific objects in the model and apply common configuration to them as seen in [Example: Default length for all string properties](#example-default-length-for-all-string-properties). This API is similar to shown in [Bulk configuration](#bulk-configuration-in-onmodelcreating). + +> [!CAUTION] +> It is advised to always perform configuration by calling methods on the builder exposed as the property, because the builders check whether the given configuration would override something that was already specified using Fluent API or Data Annotations. + +## When to use each approach for bulk configuration + +Use [Metadata API](#bulk-configuration-in-onmodelcreating) when: + +- The configuration needs to be applied at a certain time and not react to later changes in the model. +- The model building speed is very important. Metadata API has fewer safety checks and thus can be slightly faster than other approaches, however using a [Compiled model](xref:core/performance/advanced-performance-topics#compiled-models) would yield even better startup times. + +Use [Pre-convention model configuration](#pre-convention-configuration) when: + +- The applicability condition is simple as it only depends on the type. +- The configuration needs to be applied at any point a property of the given type is added in the model and overrides Data Annotations and conventions + +Use [Finalizing Conventions](#conventions) when: + +- The applicability condition is complex. +- The configuration shouldn't override what is specified by Data Annotations. + +Use [Interactive Conventions](#conventions) when: + +- Multiple conventions depend on each other. Finalizing conventions run in the order they were added and therefore can't react to changes made by later finalizing conventions. +- The logic is shared between several contexts. Interactive conventions are safer than other approaches. diff --git a/entity-framework/core/modeling/entity-properties.md b/entity-framework/core/modeling/entity-properties.md index 95876a8865..15d8349580 100644 --- a/entity-framework/core/modeling/entity-properties.md +++ b/entity-framework/core/modeling/entity-properties.md @@ -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: diff --git a/entity-framework/core/modeling/entity-types.md b/entity-framework/core/modeling/entity-types.md index d4dc83bbe4..6ae0412e5b 100644 --- a/entity-framework/core/modeling/entity-types.md +++ b/entity-framework/core/modeling/entity-types.md @@ -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)] diff --git a/entity-framework/core/modeling/index.md b/entity-framework/core/modeling/index.md index 7c2a90af52..20f0e319cd 100644 --- a/entity-framework/core/modeling/index.md +++ b/entity-framework/core/modeling/index.md @@ -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 methods [(also known as _fluent API_)](#use-fluent-api-to-configure-a-model) in , 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 method all configuration for an entity type can be extracted to a separate class implementing . +To reduce the size of the `OnModelCreating` method all configuration for an entity type can be extracted to a separate class implementing . [!code-csharp[Main](../../../samples/core/Modeling/Misc/EntityTypeConfiguration.cs?Name=IEntityTypeConfiguration)] @@ -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 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: . 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 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)); +``` diff --git a/entity-framework/core/modeling/inheritance.md b/entity-framework/core/modeling/inheritance.md index 4951a8b8a6..f44a87b508 100644 --- a/entity-framework/core/modeling/inheritance.md +++ b/entity-framework/core/modeling/inheritance.md @@ -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 diff --git a/entity-framework/core/modeling/keyless-entity-types.md b/entity-framework/core/modeling/keyless-entity-types.md index 3b970512be..10deaa4aa2 100644 --- a/entity-framework/core/modeling/keyless-entity-types.md +++ b/entity-framework/core/modeling/keyless-entity-types.md @@ -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) diff --git a/entity-framework/core/modeling/relationships.md b/entity-framework/core/modeling/relationships.md index 92018a5350..3b42a0420c 100644 --- a/entity-framework/core/modeling/relationships.md +++ b/entity-framework/core/modeling/relationships.md @@ -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)] @@ -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)] diff --git a/entity-framework/core/modeling/shadow-properties.md b/entity-framework/core/modeling/shadow-properties.md index 6807c2f5a2..d457e04a6d 100644 --- a/entity-framework/core/modeling/shadow-properties.md +++ b/entity-framework/core/modeling/shadow-properties.md @@ -13,9 +13,9 @@ 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 `` (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 ``. 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 `` (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 ``. 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: @@ -23,7 +23,7 @@ For example, the following code listing will result in a `BlogId` shadow propert ## 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 , 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)] diff --git a/entity-framework/core/modeling/table-splitting.md b/entity-framework/core/modeling/table-splitting.md index 45be299f81..a3ca91b233 100644 --- a/entity-framework/core/modeling/table-splitting.md +++ b/entity-framework/core/modeling/table-splitting.md @@ -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):