diff --git a/src/EFCore.Cosmos/Metadata/Conventions/Internal/CosmosConventionSetBuilder.cs b/src/EFCore.Cosmos/Metadata/Conventions/Internal/CosmosConventionSetBuilder.cs index 9c69b81cea4..a651c136622 100644 --- a/src/EFCore.Cosmos/Metadata/Conventions/Internal/CosmosConventionSetBuilder.cs +++ b/src/EFCore.Cosmos/Metadata/Conventions/Internal/CosmosConventionSetBuilder.cs @@ -33,101 +33,17 @@ public override ConventionSet CreateConventionSet() { var conventionSet = base.CreateConventionSet(); - conventionSet.ModelInitializedConventions.Add(new ContextContainerConvention(Dependencies)); - - conventionSet.ModelFinalizingConventions.Add(new ETagPropertyConvention()); - - var storeKeyConvention = new StoreKeyConvention(Dependencies); - var discriminatorConvention = new CosmosDiscriminatorConvention(Dependencies); - KeyDiscoveryConvention keyDiscoveryConvention = new CosmosKeyDiscoveryConvention(Dependencies); - InversePropertyAttributeConvention inversePropertyAttributeConvention = - new CosmosInversePropertyAttributeConvention(Dependencies); - RelationshipDiscoveryConvention relationshipDiscoveryConvention = - new CosmosRelationshipDiscoveryConvention(Dependencies); - conventionSet.EntityTypeAddedConventions.Add(storeKeyConvention); - conventionSet.EntityTypeAddedConventions.Add(discriminatorConvention); - ReplaceConvention(conventionSet.EntityTypeAddedConventions, keyDiscoveryConvention); - ReplaceConvention(conventionSet.EntityTypeAddedConventions, inversePropertyAttributeConvention); - ReplaceConvention(conventionSet.EntityTypeAddedConventions, relationshipDiscoveryConvention); - - ReplaceConvention(conventionSet.EntityTypeIgnoredConventions, relationshipDiscoveryConvention); - - ReplaceConvention(conventionSet.EntityTypeRemovedConventions, (DiscriminatorConvention)discriminatorConvention); - ReplaceConvention(conventionSet.EntityTypeRemovedConventions, inversePropertyAttributeConvention); - - ValueGenerationConvention valueGenerationConvention = new CosmosValueGenerationConvention(Dependencies); - conventionSet.EntityTypeBaseTypeChangedConventions.Add(storeKeyConvention); - ReplaceConvention(conventionSet.EntityTypeBaseTypeChangedConventions, valueGenerationConvention); - ReplaceConvention(conventionSet.EntityTypeBaseTypeChangedConventions, (DiscriminatorConvention)discriminatorConvention); - ReplaceConvention(conventionSet.EntityTypeBaseTypeChangedConventions, keyDiscoveryConvention); - ReplaceConvention(conventionSet.EntityTypeBaseTypeChangedConventions, inversePropertyAttributeConvention); - ReplaceConvention(conventionSet.EntityTypeBaseTypeChangedConventions, relationshipDiscoveryConvention); - - ReplaceConvention(conventionSet.EntityTypeMemberIgnoredConventions, keyDiscoveryConvention); - ReplaceConvention(conventionSet.EntityTypeMemberIgnoredConventions, inversePropertyAttributeConvention); - ReplaceConvention(conventionSet.EntityTypeMemberIgnoredConventions, relationshipDiscoveryConvention); - - conventionSet.EntityTypePrimaryKeyChangedConventions.Add(storeKeyConvention); - ReplaceConvention(conventionSet.EntityTypePrimaryKeyChangedConventions, valueGenerationConvention); - - conventionSet.KeyAddedConventions.Add(storeKeyConvention); - - conventionSet.KeyRemovedConventions.Add(storeKeyConvention); - ReplaceConvention(conventionSet.KeyRemovedConventions, keyDiscoveryConvention); - - ReplaceConvention(conventionSet.ForeignKeyAddedConventions, keyDiscoveryConvention); - ReplaceConvention(conventionSet.ForeignKeyAddedConventions, valueGenerationConvention); - - ReplaceConvention(conventionSet.ForeignKeyRemovedConventions, relationshipDiscoveryConvention); - conventionSet.ForeignKeyRemovedConventions.Add(discriminatorConvention); - conventionSet.ForeignKeyRemovedConventions.Add(storeKeyConvention); - ReplaceConvention(conventionSet.ForeignKeyRemovedConventions, keyDiscoveryConvention); - ReplaceConvention(conventionSet.ForeignKeyRemovedConventions, valueGenerationConvention); - - ReplaceConvention(conventionSet.ForeignKeyPropertiesChangedConventions, keyDiscoveryConvention); - ReplaceConvention(conventionSet.ForeignKeyPropertiesChangedConventions, valueGenerationConvention); - - ReplaceConvention(conventionSet.ForeignKeyUniquenessChangedConventions, keyDiscoveryConvention); - - conventionSet.ForeignKeyOwnershipChangedConventions.Add(discriminatorConvention); - conventionSet.ForeignKeyOwnershipChangedConventions.Add(storeKeyConvention); - ReplaceConvention(conventionSet.ForeignKeyOwnershipChangedConventions, keyDiscoveryConvention); - ReplaceConvention(conventionSet.ForeignKeyOwnershipChangedConventions, valueGenerationConvention); - ReplaceConvention(conventionSet.ForeignKeyOwnershipChangedConventions, relationshipDiscoveryConvention); - - ReplaceConvention(conventionSet.ForeignKeyNullNavigationSetConventions, relationshipDiscoveryConvention); - - ReplaceConvention(conventionSet.NavigationAddedConventions, inversePropertyAttributeConvention); - ReplaceConvention(conventionSet.NavigationAddedConventions, relationshipDiscoveryConvention); - - ReplaceConvention(conventionSet.NavigationRemovedConventions, relationshipDiscoveryConvention); - - ManyToManyJoinEntityTypeConvention manyToManyJoinEntityTypeConvention = - new CosmosManyToManyJoinEntityTypeConvention(Dependencies); - ReplaceConvention(conventionSet.SkipNavigationAddedConventions, manyToManyJoinEntityTypeConvention); - - ReplaceConvention(conventionSet.SkipNavigationRemovedConventions, manyToManyJoinEntityTypeConvention); - - ReplaceConvention(conventionSet.SkipNavigationInverseChangedConventions, manyToManyJoinEntityTypeConvention); - - ReplaceConvention(conventionSet.SkipNavigationForeignKeyChangedConventions, manyToManyJoinEntityTypeConvention); - - conventionSet.EntityTypeAnnotationChangedConventions.Add(discriminatorConvention); - conventionSet.EntityTypeAnnotationChangedConventions.Add(storeKeyConvention); - conventionSet.EntityTypeAnnotationChangedConventions.Add((CosmosValueGenerationConvention)valueGenerationConvention); - conventionSet.EntityTypeAnnotationChangedConventions.Add((CosmosKeyDiscoveryConvention)keyDiscoveryConvention); - conventionSet.EntityTypeAnnotationChangedConventions.Add( - (CosmosManyToManyJoinEntityTypeConvention)manyToManyJoinEntityTypeConvention); - - ReplaceConvention(conventionSet.PropertyAddedConventions, keyDiscoveryConvention); - - conventionSet.PropertyAnnotationChangedConventions.Add(storeKeyConvention); - - ReplaceConvention(conventionSet.ModelFinalizingConventions, inversePropertyAttributeConvention); - - ReplaceConvention( - conventionSet.ModelFinalizedConventions, - (RuntimeModelConvention)new CosmosRuntimeModelConvention(Dependencies)); + conventionSet.Add(new ContextContainerConvention(Dependencies)); + conventionSet.Add(new ETagPropertyConvention()); + conventionSet.Add(new StoreKeyConvention(Dependencies)); + + conventionSet.Replace(new CosmosValueGenerationConvention(Dependencies)); + conventionSet.Replace(new CosmosKeyDiscoveryConvention(Dependencies)); + conventionSet.Replace(new CosmosInversePropertyAttributeConvention(Dependencies)); + conventionSet.Replace(new CosmosRelationshipDiscoveryConvention(Dependencies)); + conventionSet.Replace(new CosmosDiscriminatorConvention(Dependencies)); + conventionSet.Replace(new CosmosManyToManyJoinEntityTypeConvention(Dependencies)); + conventionSet.Replace(new CosmosRuntimeModelConvention(Dependencies)); return conventionSet; } diff --git a/src/EFCore.InMemory/Metadata/Conventions/InMemoryConventionSetBuilder.cs b/src/EFCore.InMemory/Metadata/Conventions/InMemoryConventionSetBuilder.cs index 4b4f53fa7fa..5ba27e45d74 100644 --- a/src/EFCore.InMemory/Metadata/Conventions/InMemoryConventionSetBuilder.cs +++ b/src/EFCore.InMemory/Metadata/Conventions/InMemoryConventionSetBuilder.cs @@ -36,7 +36,7 @@ public override ConventionSet CreateConventionSet() { var conventionSet = base.CreateConventionSet(); - conventionSet.ModelFinalizingConventions.Add(new DefiningQueryRewritingConvention(Dependencies)); + conventionSet.Add(new DefiningQueryRewritingConvention(Dependencies)); return conventionSet; } diff --git a/src/EFCore.Proxies/Proxies/Internal/ProxiesConventionSetPlugin.cs b/src/EFCore.Proxies/Proxies/Internal/ProxiesConventionSetPlugin.cs index 034d1f0777a..989845d78e4 100644 --- a/src/EFCore.Proxies/Proxies/Internal/ProxiesConventionSetPlugin.cs +++ b/src/EFCore.Proxies/Proxies/Internal/ProxiesConventionSetPlugin.cs @@ -12,7 +12,6 @@ namespace Microsoft.EntityFrameworkCore.Proxies.Internal; public class ProxiesConventionSetPlugin : IConventionSetPlugin { private readonly IDbContextOptions _options; - private readonly IProxyFactory _proxyFactory; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -21,12 +20,10 @@ public class ProxiesConventionSetPlugin : IConventionSetPlugin /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public ProxiesConventionSetPlugin( - IProxyFactory proxyFactory, IDbContextOptions options, LazyLoaderParameterBindingFactoryDependencies lazyLoaderParameterBindingFactoryDependencies, ProviderConventionSetBuilderDependencies conventionSetBuilderDependencies) { - _proxyFactory = proxyFactory; _options = options; LazyLoaderParameterBindingFactoryDependencies = lazyLoaderParameterBindingFactoryDependencies; ConventionSetBuilderDependencies = conventionSetBuilderDependencies; @@ -63,11 +60,10 @@ public virtual ConventionSet ModifyConventions(ConventionSet conventionSet) new ProxyChangeTrackingConvention(extension), typeof(DbSetFindingConvention)); - conventionSet.ModelFinalizingConventions.Add( - new ProxyBindingRewriter( - extension, - LazyLoaderParameterBindingFactoryDependencies, - ConventionSetBuilderDependencies)); + conventionSet.Add(new ProxyBindingRewriter( + extension, + LazyLoaderParameterBindingFactoryDependencies, + ConventionSetBuilderDependencies)); return conventionSet; } diff --git a/src/EFCore.Relational/Metadata/Conventions/Infrastructure/RelationalConventionSetBuilder.cs b/src/EFCore.Relational/Metadata/Conventions/Infrastructure/RelationalConventionSetBuilder.cs index 4d21828d6bf..98e7a936cf3 100644 --- a/src/EFCore.Relational/Metadata/Conventions/Infrastructure/RelationalConventionSetBuilder.cs +++ b/src/EFCore.Relational/Metadata/Conventions/Infrastructure/RelationalConventionSetBuilder.cs @@ -58,89 +58,32 @@ public override ConventionSet CreateConventionSet() { var conventionSet = base.CreateConventionSet(); - var relationalColumnAttributeConvention = new RelationalColumnAttributeConvention(Dependencies, RelationalDependencies); - var relationalCommentAttributeConvention = new RelationalColumnCommentAttributeConvention(Dependencies, RelationalDependencies); - var relationalPropertyJsonPropertyNameAttributeConvention = new RelationalPropertyJsonPropertyNameAttributeConvention(Dependencies, RelationalDependencies); - - conventionSet.PropertyAddedConventions.Add(relationalColumnAttributeConvention); - conventionSet.PropertyAddedConventions.Add(relationalCommentAttributeConvention); - conventionSet.PropertyAddedConventions.Add(relationalPropertyJsonPropertyNameAttributeConvention); - - var relationalNavigationJsonPropertyNameAttributeConvention = new RelationalNavigationJsonPropertyNameAttributeConvention(Dependencies, RelationalDependencies); - conventionSet.NavigationAddedConventions.Add(relationalNavigationJsonPropertyNameAttributeConvention); - - var tableNameFromDbSetConvention = new TableNameFromDbSetConvention(Dependencies, RelationalDependencies); - var entitySplittingConvention = new EntitySplittingConvention(Dependencies, RelationalDependencies); - var checkConstraintConvention = new CheckConstraintConvention(Dependencies, RelationalDependencies); - var triggerConvention = new TriggerConvention(Dependencies, RelationalDependencies); - conventionSet.EntityTypeAddedConventions.Add(new RelationalTableAttributeConvention(Dependencies, RelationalDependencies)); - conventionSet.EntityTypeAddedConventions.Add( - new RelationalTableCommentAttributeConvention(Dependencies, RelationalDependencies)); - conventionSet.EntityTypeAddedConventions.Add(tableNameFromDbSetConvention); - conventionSet.EntityTypeAddedConventions.Add(entitySplittingConvention); - conventionSet.EntityTypeAddedConventions.Add(checkConstraintConvention); - conventionSet.EntityTypeAddedConventions.Add(triggerConvention); - conventionSet.EntityTypeAddedConventions.Add(new StoredProcedureConvention(Dependencies, RelationalDependencies)); - - ValueGenerationConvention valueGenerationConvention = - new RelationalValueGenerationConvention(Dependencies, RelationalDependencies); - ReplaceConvention(conventionSet.EntityTypeBaseTypeChangedConventions, valueGenerationConvention); - conventionSet.EntityTypeBaseTypeChangedConventions.Add(tableNameFromDbSetConvention); - conventionSet.EntityTypeBaseTypeChangedConventions.Add(checkConstraintConvention); - conventionSet.EntityTypeBaseTypeChangedConventions.Add(triggerConvention); - - conventionSet.EntityTypeAnnotationChangedConventions.Add(tableNameFromDbSetConvention); - - var mapToJsonConvention = new RelationalMapToJsonConvention(Dependencies, RelationalDependencies); - conventionSet.EntityTypeAnnotationChangedConventions.Add(mapToJsonConvention); - - ReplaceConvention(conventionSet.ForeignKeyPropertiesChangedConventions, valueGenerationConvention); - - ReplaceConvention(conventionSet.ForeignKeyOwnershipChangedConventions, valueGenerationConvention); - - conventionSet.EntityTypeAnnotationChangedConventions.Add((RelationalValueGenerationConvention)valueGenerationConvention); - - ReplaceConvention(conventionSet.EntityTypePrimaryKeyChangedConventions, valueGenerationConvention); - - ReplaceConvention(conventionSet.ForeignKeyAddedConventions, valueGenerationConvention); - - ReplaceConvention(conventionSet.ForeignKeyRemovedConventions, valueGenerationConvention); - - conventionSet.PropertyAddedConventions.Add(new PropertyOverridesConvention(Dependencies, RelationalDependencies)); - - conventionSet.PropertyFieldChangedConventions.Add(relationalColumnAttributeConvention); - conventionSet.PropertyFieldChangedConventions.Add(relationalCommentAttributeConvention); - - var storeGenerationConvention = new StoreGenerationConvention(Dependencies, RelationalDependencies); - conventionSet.PropertyAnnotationChangedConventions.Add(storeGenerationConvention); - conventionSet.PropertyAnnotationChangedConventions.Add((RelationalValueGenerationConvention)valueGenerationConvention); - - var dbFunctionAttributeConvention = new RelationalDbFunctionAttributeConvention(Dependencies, RelationalDependencies); - conventionSet.ModelInitializedConventions.Add(dbFunctionAttributeConvention); - - // ModelCleanupConvention would remove the entity types added by TableValuedDbFunctionConvention #15898 - ConventionSet.AddAfter( - conventionSet.ModelFinalizingConventions, - new TableValuedDbFunctionConvention(Dependencies, RelationalDependencies), - typeof(ModelCleanupConvention)); - conventionSet.ModelFinalizingConventions.Add(new TableSharingConcurrencyTokenConvention(Dependencies, RelationalDependencies)); - conventionSet.ModelFinalizingConventions.Add(dbFunctionAttributeConvention); - conventionSet.ModelFinalizingConventions.Add(tableNameFromDbSetConvention); - conventionSet.ModelFinalizingConventions.Add(storeGenerationConvention); - conventionSet.ModelFinalizingConventions.Add(entitySplittingConvention); - conventionSet.ModelFinalizingConventions.Add(new EntityTypeHierarchyMappingConvention(Dependencies, RelationalDependencies)); - conventionSet.ModelFinalizingConventions.Add(new SequenceUniquificationConvention(Dependencies, RelationalDependencies)); - conventionSet.ModelFinalizingConventions.Add(new SharedTableConvention(Dependencies, RelationalDependencies)); - ReplaceConvention( - conventionSet.ModelFinalizingConventions, - (QueryFilterRewritingConvention)new RelationalQueryFilterRewritingConvention( - Dependencies, RelationalDependencies)); - - conventionSet.ModelFinalizingConventions.Add(mapToJsonConvention); - - ReplaceConvention( - conventionSet.ModelFinalizedConventions, - (RuntimeModelConvention)new RelationalRuntimeModelConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new RelationalColumnAttributeConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new RelationalColumnCommentAttributeConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new RelationalTableAttributeConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new RelationalTableCommentAttributeConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new RelationalDbFunctionAttributeConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new RelationalPropertyJsonPropertyNameAttributeConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new RelationalNavigationJsonPropertyNameAttributeConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new TableSharingConcurrencyTokenConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new TableNameFromDbSetConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new PropertyOverridesConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new CheckConstraintConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new TriggerConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new StoredProcedureConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new TableValuedDbFunctionConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new StoreGenerationConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new EntitySplittingConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new EntityTypeHierarchyMappingConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new SequenceUniquificationConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new SharedTableConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new RelationalMapToJsonConvention(Dependencies, RelationalDependencies)); + + conventionSet.Replace( + new RelationalValueGenerationConvention(Dependencies, RelationalDependencies)); + conventionSet.Replace( + new RelationalQueryFilterRewritingConvention(Dependencies, RelationalDependencies)); + conventionSet.Replace(new RelationalRuntimeModelConvention(Dependencies, RelationalDependencies)); return conventionSet; } diff --git a/src/EFCore.Relational/Metadata/Conventions/RelationalNavigationJsonPropertyNameAttributeConvention.cs b/src/EFCore.Relational/Metadata/Conventions/RelationalNavigationJsonPropertyNameAttributeConvention.cs index 6ed6da36af3..7ae5957dc14 100644 --- a/src/EFCore.Relational/Metadata/Conventions/RelationalNavigationJsonPropertyNameAttributeConvention.cs +++ b/src/EFCore.Relational/Metadata/Conventions/RelationalNavigationJsonPropertyNameAttributeConvention.cs @@ -12,7 +12,9 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions; /// /// See Model building conventions for more information and examples. /// -public class RelationalNavigationJsonPropertyNameAttributeConvention : NavigationAttributeConventionBase +public class RelationalNavigationJsonPropertyNameAttributeConvention : + NavigationAttributeConventionBase, + INavigationAddedConvention { /// /// Creates a new instance of . diff --git a/src/EFCore.Relational/Migrations/HistoryRepository.cs b/src/EFCore.Relational/Migrations/HistoryRepository.cs index 2f223db976c..ed111047ece 100644 --- a/src/EFCore.Relational/Migrations/HistoryRepository.cs +++ b/src/EFCore.Relational/Migrations/HistoryRepository.cs @@ -85,9 +85,8 @@ private IModel EnsureModel() { var conventionSet = Dependencies.ConventionSetBuilder.CreateConventionSet(); - // Use public API to remove the convention, issue #214 - ConventionSet.Remove(conventionSet.ModelInitializedConventions, typeof(DbSetFindingConvention)); - ConventionSet.Remove(conventionSet.ModelInitializedConventions, typeof(RelationalDbFunctionAttributeConvention)); + conventionSet.Remove(typeof(DbSetFindingConvention)); + conventionSet.Remove(typeof(RelationalDbFunctionAttributeConvention)); var modelBuilder = new ModelBuilder(conventionSet); modelBuilder.Entity( diff --git a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs index 655f1ca1963..e3cef7b1da7 100644 --- a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs +++ b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerConventionSetBuilder.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. - - // ReSharper disable once CheckNamespace namespace Microsoft.EntityFrameworkCore.Metadata.Conventions; @@ -50,82 +48,28 @@ public override ConventionSet CreateConventionSet() { var conventionSet = base.CreateConventionSet(); - var valueGenerationStrategyConvention = new SqlServerValueGenerationStrategyConvention(Dependencies, RelationalDependencies); - conventionSet.ModelInitializedConventions.Add(valueGenerationStrategyConvention); - conventionSet.ModelInitializedConventions.Add( - new RelationalMaxIdentifierLengthConvention(128, Dependencies, RelationalDependencies)); - - ValueGenerationConvention valueGenerationConvention = - new SqlServerValueGenerationConvention(Dependencies, RelationalDependencies); - var sqlServerIndexConvention = new SqlServerIndexConvention(Dependencies, RelationalDependencies, _sqlGenerationHelper); - ReplaceConvention(conventionSet.EntityTypeBaseTypeChangedConventions, valueGenerationConvention); - conventionSet.EntityTypeBaseTypeChangedConventions.Add(sqlServerIndexConvention); - - var sqlServerInMemoryTablesConvention = new SqlServerMemoryOptimizedTablesConvention(Dependencies, RelationalDependencies); - conventionSet.EntityTypeAnnotationChangedConventions.Add(sqlServerInMemoryTablesConvention); - - ReplaceConvention( - conventionSet.ForeignKeyPropertiesChangedConventions, - (RelationalValueGenerationConvention)valueGenerationConvention); - - ReplaceConvention( - conventionSet.ForeignKeyOwnershipChangedConventions, - (RelationalValueGenerationConvention)valueGenerationConvention); - - ReplaceConvention( - conventionSet.EntityTypeAnnotationChangedConventions, - (RelationalValueGenerationConvention)valueGenerationConvention); - + conventionSet.Add(new SqlServerValueGenerationStrategyConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new RelationalMaxIdentifierLengthConvention(128, Dependencies, RelationalDependencies)); + conventionSet.Add(new SqlServerIndexConvention(Dependencies, RelationalDependencies, _sqlGenerationHelper)); + conventionSet.Add(new SqlServerMemoryOptimizedTablesConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new SqlServerDbFunctionConvention(Dependencies, RelationalDependencies)); + + conventionSet.Replace( + new SqlServerOnDeleteConvention(Dependencies, RelationalDependencies)); + conventionSet.Replace( + new SqlServerStoreGenerationConvention(Dependencies, RelationalDependencies)); + conventionSet.Replace( + new SqlServerValueGenerationConvention(Dependencies, RelationalDependencies)); + conventionSet.Replace(new SqlServerRuntimeModelConvention(Dependencies, RelationalDependencies)); + var sqlServerTemporalConvention = new SqlServerTemporalConvention(Dependencies, RelationalDependencies); ConventionSet.AddBefore( conventionSet.EntityTypeAnnotationChangedConventions, sqlServerTemporalConvention, typeof(SqlServerValueGenerationConvention)); - - ReplaceConvention(conventionSet.EntityTypePrimaryKeyChangedConventions, valueGenerationConvention); - - conventionSet.KeyAddedConventions.Add(sqlServerInMemoryTablesConvention); - - var sqlServerOnDeleteConvention = new SqlServerOnDeleteConvention(Dependencies, RelationalDependencies); - ReplaceConvention(conventionSet.ForeignKeyAddedConventions, valueGenerationConvention); - ReplaceConvention(conventionSet.ForeignKeyAddedConventions, (CascadeDeleteConvention)sqlServerOnDeleteConvention); - - ReplaceConvention(conventionSet.ForeignKeyRemovedConventions, valueGenerationConvention); - - ReplaceConvention(conventionSet.ForeignKeyRequirednessChangedConventions, (CascadeDeleteConvention)sqlServerOnDeleteConvention); - - conventionSet.SkipNavigationForeignKeyChangedConventions.Add(sqlServerOnDeleteConvention); - - conventionSet.IndexAddedConventions.Add(sqlServerInMemoryTablesConvention); - conventionSet.IndexAddedConventions.Add(sqlServerIndexConvention); - - conventionSet.IndexUniquenessChangedConventions.Add(sqlServerIndexConvention); - - conventionSet.IndexAnnotationChangedConventions.Add(sqlServerIndexConvention); - - conventionSet.PropertyNullabilityChangedConventions.Add(sqlServerIndexConvention); - - StoreGenerationConvention storeGenerationConvention = - new SqlServerStoreGenerationConvention(Dependencies, RelationalDependencies); - conventionSet.PropertyAnnotationChangedConventions.Add(sqlServerIndexConvention); - ReplaceConvention(conventionSet.PropertyAnnotationChangedConventions, storeGenerationConvention); - ReplaceConvention( - conventionSet.PropertyAnnotationChangedConventions, (RelationalValueGenerationConvention)valueGenerationConvention); - - conventionSet.ModelFinalizingConventions.Add(valueGenerationStrategyConvention); - ReplaceConvention(conventionSet.ModelFinalizingConventions, storeGenerationConvention); - ReplaceConvention( - conventionSet.ModelFinalizingConventions, - (SharedTableConvention)new SqlServerSharedTableConvention(Dependencies, RelationalDependencies)); - conventionSet.ModelFinalizingConventions.Add(new SqlServerDbFunctionConvention(Dependencies, RelationalDependencies)); - conventionSet.ModelFinalizingConventions.Add(sqlServerTemporalConvention); - - ReplaceConvention( - conventionSet.ModelFinalizedConventions, - (RuntimeModelConvention)new SqlServerRuntimeModelConvention(Dependencies, RelationalDependencies)); - conventionSet.SkipNavigationForeignKeyChangedConventions.Add(sqlServerTemporalConvention); - + conventionSet.ModelFinalizingConventions.Add(sqlServerTemporalConvention); + return conventionSet; } diff --git a/src/EFCore.Sqlite.Core/Metadata/Conventions/SqliteConventionSetBuilder.cs b/src/EFCore.Sqlite.Core/Metadata/Conventions/SqliteConventionSetBuilder.cs index 3dba10a3771..5f8f23415ac 100644 --- a/src/EFCore.Sqlite.Core/Metadata/Conventions/SqliteConventionSetBuilder.cs +++ b/src/EFCore.Sqlite.Core/Metadata/Conventions/SqliteConventionSetBuilder.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. - - // ReSharper disable once CheckNamespace namespace Microsoft.EntityFrameworkCore.Metadata.Conventions; @@ -44,13 +42,8 @@ public override ConventionSet CreateConventionSet() { var conventionSet = base.CreateConventionSet(); - ReplaceConvention( - conventionSet.ModelFinalizingConventions, - (SharedTableConvention)new SqliteSharedTableConvention(Dependencies, RelationalDependencies)); - - ReplaceConvention( - conventionSet.ModelFinalizedConventions, - (RuntimeModelConvention)new SqliteRuntimeModelConvention(Dependencies, RelationalDependencies)); + conventionSet.Replace(new SqliteSharedTableConvention(Dependencies, RelationalDependencies)); + conventionSet.Replace(new SqliteRuntimeModelConvention(Dependencies, RelationalDependencies)); return conventionSet; } diff --git a/src/EFCore/Metadata/Builders/IConventionEntityTypeBuilder.cs b/src/EFCore/Metadata/Builders/IConventionEntityTypeBuilder.cs index 178970003f1..824e6d9eb32 100644 --- a/src/EFCore/Metadata/Builders/IConventionEntityTypeBuilder.cs +++ b/src/EFCore/Metadata/Builders/IConventionEntityTypeBuilder.cs @@ -241,6 +241,14 @@ bool CanHaveIndexerProperty( /// otherwise. /// IConventionKeyBuilder? PrimaryKey(IReadOnlyList? propertyNames, bool fromDataAnnotation = false); + + /// + /// Returns a value indicating whether the given properties can be set as the primary key for this entity type. + /// + /// The names of the properties that make up the index. + /// Indicates whether the configuration was specified using a data annotation. + /// if the given properties can be set as the primary key. + bool CanSetPrimaryKey(IReadOnlyList propertyNames, bool fromDataAnnotation = false); /// /// Returns a value indicating whether the given properties can be set as the primary key for this entity type. @@ -369,6 +377,14 @@ bool CanHaveIndexerProperty( IReadOnlyList properties, string name, bool fromDataAnnotation = false); + + /// + /// Returns a value indicating whether and index on the given properties can be added to this entity type. + /// + /// The names of the properties that make up the index. + /// Indicates whether the configuration was specified using a data annotation. + /// if the index can be added. + bool CanHaveIndex(IReadOnlyList propertyNames, bool fromDataAnnotation = false); /// /// Removes an index from this entity type. diff --git a/src/EFCore/Metadata/Conventions/ConventionSet.cs b/src/EFCore/Metadata/Conventions/ConventionSet.cs index 54cc3869801..663e30b0250 100644 --- a/src/EFCore/Metadata/Conventions/ConventionSet.cs +++ b/src/EFCore/Metadata/Conventions/ConventionSet.cs @@ -14,238 +14,476 @@ public class ConventionSet /// /// Conventions to run to setup the initial model. /// - public virtual IList ModelInitializedConventions { get; } = new List(); + public virtual List ModelInitializedConventions { get; } = new(); /// /// Conventions to run when model building is completed. /// - public virtual IList ModelFinalizingConventions { get; } = new List(); + public virtual List ModelFinalizingConventions { get; } = new(); /// /// Conventions to run when model validation is completed. /// - public virtual IList ModelFinalizedConventions { get; } = new List(); + public virtual List ModelFinalizedConventions { get; } = new(); /// /// Conventions to run when an annotation is set or removed on a model. /// - public virtual IList ModelAnnotationChangedConventions { get; } - = new List(); + public virtual List ModelAnnotationChangedConventions { get; } = new(); /// /// Conventions to run when an entity type is added to the model. /// - public virtual IList EntityTypeAddedConventions { get; } = new List(); + public virtual List EntityTypeAddedConventions { get; } = new(); /// /// Conventions to run when an entity type is ignored. /// - public virtual IList EntityTypeIgnoredConventions { get; } = new List(); + public virtual List EntityTypeIgnoredConventions { get; } = new(); /// /// Conventions to run when an entity type is removed. /// - public virtual IList EntityTypeRemovedConventions { get; } = new List(); + public virtual List EntityTypeRemovedConventions { get; } = new(); /// /// Conventions to run when a property is ignored. /// - public virtual IList EntityTypeMemberIgnoredConventions { get; } - = new List(); + public virtual List EntityTypeMemberIgnoredConventions { get; } = new(); /// /// Conventions to run when the base entity type is changed. /// - public virtual IList EntityTypeBaseTypeChangedConventions { get; } - = new List(); + public virtual List EntityTypeBaseTypeChangedConventions { get; } = new(); /// /// Conventions to run when a primary key is changed. /// - public virtual IList EntityTypePrimaryKeyChangedConventions { get; } - = new List(); + public virtual List EntityTypePrimaryKeyChangedConventions { get; } = new(); /// /// Conventions to run when an annotation is set or removed on an entity type. /// - public virtual IList EntityTypeAnnotationChangedConventions { get; } - = new List(); + public virtual List EntityTypeAnnotationChangedConventions { get; } = new(); /// /// Conventions to run when a foreign key is added. /// - public virtual IList ForeignKeyAddedConventions { get; } = new List(); + public virtual List ForeignKeyAddedConventions { get; } = new(); /// /// Conventions to run when a foreign key is removed. /// - public virtual IList ForeignKeyRemovedConventions { get; } = new List(); + public virtual List ForeignKeyRemovedConventions { get; } = new(); /// /// Conventions to run when the principal end of a relationship is configured. /// - public virtual IList ForeignKeyPrincipalEndChangedConventions { get; } - = new List(); + public virtual List ForeignKeyPrincipalEndChangedConventions { get; } = new(); /// /// Conventions to run when the properties or the principal key of a foreign key are changed. /// - public virtual IList ForeignKeyPropertiesChangedConventions { get; } - = new List(); + public virtual List ForeignKeyPropertiesChangedConventions { get; } = new(); /// /// Conventions to run when the uniqueness of a foreign key is changed. /// - public virtual IList ForeignKeyUniquenessChangedConventions { get; } - = new List(); + public virtual List ForeignKeyUniquenessChangedConventions { get; } = new(); /// /// Conventions to run when the requiredness of a foreign key is changed. /// - public virtual IList ForeignKeyRequirednessChangedConventions { get; } - = new List(); + public virtual List ForeignKeyRequirednessChangedConventions { get; } = new(); /// /// Conventions to run when the requiredness of a foreign key is changed. /// - public virtual IList ForeignKeyDependentRequirednessChangedConventions { get; } - = new List(); + public virtual List ForeignKeyDependentRequirednessChangedConventions { get; } + = new(); /// /// Conventions to run when the ownership of a foreign key is changed. /// - public virtual IList ForeignKeyOwnershipChangedConventions { get; } - = new List(); + public virtual List ForeignKeyOwnershipChangedConventions { get; } = new(); /// /// Conventions to run when an annotation is changed on a foreign key. /// - public virtual IList ForeignKeyAnnotationChangedConventions { get; } - = new List(); + public virtual List ForeignKeyAnnotationChangedConventions { get; } = new(); /// /// Conventions to run when a navigation is set to on a foreign key. /// - public virtual IList ForeignKeyNullNavigationSetConventions { get; } - = new List(); + public virtual List ForeignKeyNullNavigationSetConventions { get; } = new(); /// /// Conventions to run when a navigation property is added. /// - public virtual IList NavigationAddedConventions { get; } = new List(); + public virtual List NavigationAddedConventions { get; } = new(); /// /// Conventions to run when an annotation is changed on a navigation property. /// - public virtual IList NavigationAnnotationChangedConventions { get; } - = new List(); + public virtual List NavigationAnnotationChangedConventions { get; } = new(); /// /// Conventions to run when a navigation property is removed. /// - public virtual IList NavigationRemovedConventions { get; } = new List(); + public virtual List NavigationRemovedConventions { get; } = new(); /// /// Conventions to run when a skip navigation property is added. /// - public virtual IList SkipNavigationAddedConventions { get; } - = new List(); + public virtual List SkipNavigationAddedConventions { get; } = new(); /// /// Conventions to run when an annotation is changed on a skip navigation property. /// - public virtual IList SkipNavigationAnnotationChangedConventions { get; } - = new List(); + public virtual List SkipNavigationAnnotationChangedConventions { get; } = new(); /// /// Conventions to run when a skip navigation foreign key is changed. /// - public virtual IList SkipNavigationForeignKeyChangedConventions { get; } - = new List(); + public virtual List SkipNavigationForeignKeyChangedConventions { get; } = new(); /// /// Conventions to run when a skip navigation inverse is changed. /// - public virtual IList SkipNavigationInverseChangedConventions { get; } - = new List(); + public virtual List SkipNavigationInverseChangedConventions { get; } = new(); /// /// Conventions to run when a skip navigation property is removed. /// - public virtual IList SkipNavigationRemovedConventions { get; } - = new List(); + public virtual List SkipNavigationRemovedConventions { get; } = new(); /// /// Conventions to run when a key is added. /// - public virtual IList KeyAddedConventions { get; } = new List(); + public virtual List KeyAddedConventions { get; } = new(); /// /// Conventions to run when a key is removed. /// - public virtual IList KeyRemovedConventions { get; } = new List(); + public virtual List KeyRemovedConventions { get; } = new(); /// /// Conventions to run when an annotation is changed on a key. /// - public virtual IList KeyAnnotationChangedConventions { get; } - = new List(); + public virtual List KeyAnnotationChangedConventions { get; } = new(); /// /// Conventions to run when an index is added. /// - public virtual IList IndexAddedConventions { get; } = new List(); + public virtual List IndexAddedConventions { get; } = new(); /// /// Conventions to run when an index is removed. /// - public virtual IList IndexRemovedConventions { get; } = new List(); + public virtual List IndexRemovedConventions { get; } = new(); /// /// Conventions to run when the uniqueness of an index is changed. /// - public virtual IList IndexUniquenessChangedConventions { get; } - = new List(); + public virtual List IndexUniquenessChangedConventions { get; } = new(); /// /// Conventions to run when the sort order of an index is changed. /// - public virtual IList IndexSortOrderChangedConventions { get; } - = new List(); + public virtual List IndexSortOrderChangedConventions { get; } = new(); /// /// Conventions to run when an annotation is changed on an index. /// - public virtual IList IndexAnnotationChangedConventions { get; } - = new List(); + public virtual List IndexAnnotationChangedConventions { get; } = new(); /// /// Conventions to run when a property is added. /// - public virtual IList PropertyAddedConventions { get; } = new List(); + public virtual List PropertyAddedConventions { get; } = new(); /// /// Conventions to run when the nullability of a property is changed. /// - public virtual IList PropertyNullabilityChangedConventions { get; } - = new List(); + public virtual List PropertyNullabilityChangedConventions { get; } = new(); /// /// Conventions to run when the field of a property is changed. /// - public virtual IList PropertyFieldChangedConventions { get; } - = new List(); + public virtual List PropertyFieldChangedConventions { get; } = new(); /// /// Conventions to run when an annotation is changed on a property. /// - public virtual IList PropertyAnnotationChangedConventions { get; } - = new List(); + public virtual List PropertyAnnotationChangedConventions { get; } = new(); /// /// Conventions to run when a property is removed. /// - public virtual IList PropertyRemovedConventions { get; } = new List(); + public virtual List PropertyRemovedConventions { get; } = new(); + + /// + /// Replaces an existing convention with a derived convention. Also registers the new convention for any + /// convention types not implemented by the existing convention. + /// + /// The type of the old convention. + /// The new convention. + public virtual void Replace(TImplementation newConvention) + where TImplementation : IConvention + { + var oldConvetionType = typeof(TImplementation); + if (newConvention is IModelInitializedConvention modelInitializedConvention + && !Replace(ModelInitializedConventions, modelInitializedConvention, oldConvetionType)) + { + ModelInitializedConventions.Add(modelInitializedConvention); + } + + if (newConvention is IModelFinalizingConvention modelFinalizingConvention + && !Replace(ModelFinalizingConventions, modelFinalizingConvention, oldConvetionType)) + { + ModelFinalizingConventions.Add(modelFinalizingConvention); + } + + if (newConvention is IModelFinalizedConvention modelFinalizedConvention + && !Replace(ModelFinalizedConventions, modelFinalizedConvention, oldConvetionType)) + { + ModelFinalizedConventions.Add(modelFinalizedConvention); + } + + if (newConvention is IModelAnnotationChangedConvention modelAnnotationChangedConvention + && !Replace(ModelAnnotationChangedConventions, modelAnnotationChangedConvention, oldConvetionType)) + { + ModelAnnotationChangedConventions.Add(modelAnnotationChangedConvention); + } + + if (newConvention is IEntityTypeAddedConvention entityTypeAddedConvention + && !Replace(EntityTypeAddedConventions, entityTypeAddedConvention, oldConvetionType)) + { + EntityTypeAddedConventions.Add(entityTypeAddedConvention); + } + + if (newConvention is IEntityTypeIgnoredConvention entityTypeIgnoredConvention + && !Replace(EntityTypeIgnoredConventions, entityTypeIgnoredConvention, oldConvetionType)) + { + EntityTypeIgnoredConventions.Add(entityTypeIgnoredConvention); + } + + if (newConvention is IEntityTypeRemovedConvention entityTypeRemovedConvention + && !Replace(EntityTypeRemovedConventions, entityTypeRemovedConvention, oldConvetionType)) + { + EntityTypeRemovedConventions.Add(entityTypeRemovedConvention); + } + + if (newConvention is IEntityTypeMemberIgnoredConvention entityTypeMemberIgnoredConvention + && !Replace(EntityTypeMemberIgnoredConventions, entityTypeMemberIgnoredConvention, oldConvetionType)) + { + EntityTypeMemberIgnoredConventions.Add(entityTypeMemberIgnoredConvention); + } + + if (newConvention is IEntityTypeBaseTypeChangedConvention entityTypeBaseTypeChangedConvention + && !Replace(EntityTypeBaseTypeChangedConventions, entityTypeBaseTypeChangedConvention, oldConvetionType)) + { + EntityTypeBaseTypeChangedConventions.Add(entityTypeBaseTypeChangedConvention); + } + + if (newConvention is IEntityTypePrimaryKeyChangedConvention entityTypePrimaryKeyChangedConvention + && !Replace(EntityTypePrimaryKeyChangedConventions, entityTypePrimaryKeyChangedConvention, oldConvetionType)) + { + EntityTypePrimaryKeyChangedConventions.Add(entityTypePrimaryKeyChangedConvention); + } + + if (newConvention is IEntityTypeAnnotationChangedConvention entityTypeAnnotationChangedConvention + && !Replace(EntityTypeAnnotationChangedConventions, entityTypeAnnotationChangedConvention, oldConvetionType)) + { + EntityTypeAnnotationChangedConventions.Add(entityTypeAnnotationChangedConvention); + } + + if (newConvention is IForeignKeyAddedConvention foreignKeyAddedConvention + && !Replace(ForeignKeyAddedConventions, foreignKeyAddedConvention, oldConvetionType)) + { + ForeignKeyAddedConventions.Add(foreignKeyAddedConvention); + } + + if (newConvention is IForeignKeyRemovedConvention foreignKeyRemovedConvention + && !Replace(ForeignKeyRemovedConventions, foreignKeyRemovedConvention, oldConvetionType)) + { + ForeignKeyRemovedConventions.Add(foreignKeyRemovedConvention); + } + + if (newConvention is IForeignKeyPrincipalEndChangedConvention foreignKeyPrincipalEndChangedConvention + && !Replace(ForeignKeyPrincipalEndChangedConventions, foreignKeyPrincipalEndChangedConvention, oldConvetionType)) + { + ForeignKeyPrincipalEndChangedConventions.Add(foreignKeyPrincipalEndChangedConvention); + } + + if (newConvention is IForeignKeyPropertiesChangedConvention foreignKeyPropertiesChangedConvention + && !Replace(ForeignKeyPropertiesChangedConventions, foreignKeyPropertiesChangedConvention, oldConvetionType)) + { + ForeignKeyPropertiesChangedConventions.Add(foreignKeyPropertiesChangedConvention); + } + + if (newConvention is IForeignKeyUniquenessChangedConvention foreignKeyUniquenessChangedConvention + && !Replace(ForeignKeyUniquenessChangedConventions, foreignKeyUniquenessChangedConvention, oldConvetionType)) + { + ForeignKeyUniquenessChangedConventions.Add(foreignKeyUniquenessChangedConvention); + } + + if (newConvention is IForeignKeyRequirednessChangedConvention foreignKeyRequirednessChangedConvention + && !Replace(ForeignKeyRequirednessChangedConventions, foreignKeyRequirednessChangedConvention, oldConvetionType)) + { + ForeignKeyRequirednessChangedConventions.Add(foreignKeyRequirednessChangedConvention); + } + + if (newConvention is IForeignKeyDependentRequirednessChangedConvention foreignKeyDependentRequirednessChangedConvention + && !Replace(ForeignKeyDependentRequirednessChangedConventions, foreignKeyDependentRequirednessChangedConvention, oldConvetionType)) + { + ForeignKeyDependentRequirednessChangedConventions.Add(foreignKeyDependentRequirednessChangedConvention); + } + + if (newConvention is IForeignKeyOwnershipChangedConvention foreignKeyOwnershipChangedConvention + && !Replace(ForeignKeyOwnershipChangedConventions, foreignKeyOwnershipChangedConvention, oldConvetionType)) + { + ForeignKeyOwnershipChangedConventions.Add(foreignKeyOwnershipChangedConvention); + } + + if (newConvention is IForeignKeyAnnotationChangedConvention foreignKeyAnnotationChangedConvention + && !Replace(ForeignKeyAnnotationChangedConventions, foreignKeyAnnotationChangedConvention, oldConvetionType)) + { + ForeignKeyAnnotationChangedConventions.Add(foreignKeyAnnotationChangedConvention); + } + + if (newConvention is IForeignKeyNullNavigationSetConvention foreignKeyNullNavigationSetConvention + && !Replace(ForeignKeyNullNavigationSetConventions, foreignKeyNullNavigationSetConvention, oldConvetionType)) + { + ForeignKeyNullNavigationSetConventions.Add(foreignKeyNullNavigationSetConvention); + } + + if (newConvention is INavigationAddedConvention navigationAddedConvention + && !Replace(NavigationAddedConventions, navigationAddedConvention, oldConvetionType)) + { + NavigationAddedConventions.Add(navigationAddedConvention); + } + + if (newConvention is INavigationAnnotationChangedConvention navigationAnnotationChangedConvention + && !Replace(NavigationAnnotationChangedConventions, navigationAnnotationChangedConvention, oldConvetionType)) + { + NavigationAnnotationChangedConventions.Add(navigationAnnotationChangedConvention); + } + + if (newConvention is INavigationRemovedConvention navigationRemovedConvention + && !Replace(NavigationRemovedConventions, navigationRemovedConvention, oldConvetionType)) + { + NavigationRemovedConventions.Add(navigationRemovedConvention); + } + + if (newConvention is ISkipNavigationAddedConvention skipNavigationAddedConvention + && !Replace(SkipNavigationAddedConventions, skipNavigationAddedConvention, oldConvetionType)) + { + SkipNavigationAddedConventions.Add(skipNavigationAddedConvention); + } + + if (newConvention is ISkipNavigationAnnotationChangedConvention skipNavigationAnnotationChangedConvention + && !Replace(SkipNavigationAnnotationChangedConventions, skipNavigationAnnotationChangedConvention, oldConvetionType)) + { + SkipNavigationAnnotationChangedConventions.Add(skipNavigationAnnotationChangedConvention); + } + + if (newConvention is ISkipNavigationForeignKeyChangedConvention skipNavigationForeignKeyChangedConvention + && !Replace(SkipNavigationForeignKeyChangedConventions, skipNavigationForeignKeyChangedConvention, oldConvetionType)) + { + SkipNavigationForeignKeyChangedConventions.Add(skipNavigationForeignKeyChangedConvention); + } + + if (newConvention is ISkipNavigationInverseChangedConvention skipNavigationInverseChangedConvention + && !Replace(SkipNavigationInverseChangedConventions, skipNavigationInverseChangedConvention, oldConvetionType)) + { + SkipNavigationInverseChangedConventions.Add(skipNavigationInverseChangedConvention); + } + + if (newConvention is ISkipNavigationRemovedConvention skipNavigationRemovedConvention + && !Replace(SkipNavigationRemovedConventions, skipNavigationRemovedConvention, oldConvetionType)) + { + SkipNavigationRemovedConventions.Add(skipNavigationRemovedConvention); + } + + if (newConvention is IKeyAddedConvention keyAddedConvention + && !Replace(KeyAddedConventions, keyAddedConvention, oldConvetionType)) + { + KeyAddedConventions.Add(keyAddedConvention); + } + + if (newConvention is IKeyRemovedConvention keyRemovedConvention + && !Replace(KeyRemovedConventions, keyRemovedConvention, oldConvetionType)) + { + KeyRemovedConventions.Add(keyRemovedConvention); + } + + if (newConvention is IKeyAnnotationChangedConvention keyAnnotationChangedConvention + && !Replace(KeyAnnotationChangedConventions, keyAnnotationChangedConvention, oldConvetionType)) + { + KeyAnnotationChangedConventions.Add(keyAnnotationChangedConvention); + } + + if (newConvention is IIndexAddedConvention indexAddedConvention + && !Replace(IndexAddedConventions, indexAddedConvention, oldConvetionType)) + { + IndexAddedConventions.Add(indexAddedConvention); + } + + if (newConvention is IIndexRemovedConvention indexRemovedConvention + && !Replace(IndexRemovedConventions, indexRemovedConvention, oldConvetionType)) + { + IndexRemovedConventions.Add(indexRemovedConvention); + } + + if (newConvention is IIndexUniquenessChangedConvention indexUniquenessChangedConvention + && !Replace(IndexUniquenessChangedConventions, indexUniquenessChangedConvention, oldConvetionType)) + { + IndexUniquenessChangedConventions.Add(indexUniquenessChangedConvention); + } + + if (newConvention is IIndexSortOrderChangedConvention indexSortOrderChangedConvention + && !Replace(IndexSortOrderChangedConventions, indexSortOrderChangedConvention, oldConvetionType)) + { + IndexSortOrderChangedConventions.Add(indexSortOrderChangedConvention); + } + + if (newConvention is IIndexAnnotationChangedConvention indexAnnotationChangedConvention + && !Replace(IndexAnnotationChangedConventions, indexAnnotationChangedConvention, oldConvetionType)) + { + IndexAnnotationChangedConventions.Add(indexAnnotationChangedConvention); + } + + if (newConvention is IPropertyAddedConvention propertyAddedConvention + && !Replace(PropertyAddedConventions, propertyAddedConvention, oldConvetionType)) + { + PropertyAddedConventions.Add(propertyAddedConvention); + } + + if (newConvention is IPropertyNullabilityChangedConvention propertyNullabilityChangedConvention + && !Replace(PropertyNullabilityChangedConventions, propertyNullabilityChangedConvention, oldConvetionType)) + { + PropertyNullabilityChangedConventions.Add(propertyNullabilityChangedConvention); + } + + if (newConvention is IPropertyFieldChangedConvention propertyFieldChangedConvention + && !Replace(PropertyFieldChangedConventions, propertyFieldChangedConvention, oldConvetionType)) + { + PropertyFieldChangedConventions.Add(propertyFieldChangedConvention); + } + + if (newConvention is IPropertyAnnotationChangedConvention propertyAnnotationChangedConvention + && !Replace(PropertyAnnotationChangedConventions, propertyAnnotationChangedConvention, oldConvetionType)) + { + PropertyAnnotationChangedConventions.Add(propertyAnnotationChangedConvention); + } + + if (newConvention is IPropertyRemovedConvention propertyRemovedConvention + && !Replace(PropertyRemovedConventions, propertyRemovedConvention, oldConvetionType)) + { + PropertyRemovedConventions.Add(propertyRemovedConvention); + } + } /// /// Replaces an existing convention with a derived convention. @@ -256,16 +494,27 @@ public class ConventionSet /// The new convention. /// if the convention was replaced. public static bool Replace( - IList conventionsList, + List conventionsList, TImplementation newConvention) where TImplementation : TConvention { Check.NotNull(conventionsList, nameof(conventionsList)); Check.NotNull(newConvention, nameof(newConvention)); + return Replace(conventionsList, newConvention, typeof(TImplementation)); + } + + private static bool Replace( + List conventionsList, + TConvention newConvention, + Type oldConventionType) + { + Check.NotNull(conventionsList, nameof(conventionsList)); + Check.NotNull(newConvention, nameof(newConvention)); + for (var i = 0; i < conventionsList.Count; i++) { - if (conventionsList[i] is TImplementation) + if (oldConventionType.IsInstanceOfType(conventionsList[i]!)) { conventionsList.RemoveAt(i); conventionsList.Insert(i, newConvention); @@ -276,6 +525,223 @@ public static bool Replace( return false; } + /// + /// Adds a convention to the set. + /// + /// The convention to add. + public virtual void Add(IConvention convention) + { + if (convention is IModelInitializedConvention modelInitializedConvention) + { + ModelInitializedConventions.Add(modelInitializedConvention); + } + + if (convention is IModelFinalizingConvention modelFinalizingConvention) + { + ModelFinalizingConventions.Add(modelFinalizingConvention); + } + + if (convention is IModelFinalizedConvention modelFinalizedConvention) + { + ModelFinalizedConventions.Add(modelFinalizedConvention); + } + + if (convention is IModelAnnotationChangedConvention modelAnnotationChangedConvention) + { + ModelAnnotationChangedConventions.Add(modelAnnotationChangedConvention); + } + + if (convention is IEntityTypeAddedConvention entityTypeAddedConvention) + { + EntityTypeAddedConventions.Add(entityTypeAddedConvention); + } + + if (convention is IEntityTypeIgnoredConvention entityTypeIgnoredConvention) + { + EntityTypeIgnoredConventions.Add(entityTypeIgnoredConvention); + } + + if (convention is IEntityTypeRemovedConvention entityTypeRemovedConvention) + { + EntityTypeRemovedConventions.Add(entityTypeRemovedConvention); + } + + if (convention is IEntityTypeMemberIgnoredConvention entityTypeMemberIgnoredConvention) + { + EntityTypeMemberIgnoredConventions.Add(entityTypeMemberIgnoredConvention); + } + + if (convention is IEntityTypeBaseTypeChangedConvention entityTypeBaseTypeChangedConvention) + { + EntityTypeBaseTypeChangedConventions.Add(entityTypeBaseTypeChangedConvention); + } + + if (convention is IEntityTypePrimaryKeyChangedConvention entityTypePrimaryKeyChangedConvention) + { + EntityTypePrimaryKeyChangedConventions.Add(entityTypePrimaryKeyChangedConvention); + } + + if (convention is IEntityTypeAnnotationChangedConvention entityTypeAnnotationChangedConvention) + { + EntityTypeAnnotationChangedConventions.Add(entityTypeAnnotationChangedConvention); + } + + if (convention is IForeignKeyAddedConvention foreignKeyAddedConvention) + { + ForeignKeyAddedConventions.Add(foreignKeyAddedConvention); + } + + if (convention is IForeignKeyRemovedConvention foreignKeyRemovedConvention) + { + ForeignKeyRemovedConventions.Add(foreignKeyRemovedConvention); + } + + if (convention is IForeignKeyPrincipalEndChangedConvention foreignKeyPrincipalEndChangedConvention) + { + ForeignKeyPrincipalEndChangedConventions.Add(foreignKeyPrincipalEndChangedConvention); + } + + if (convention is IForeignKeyPropertiesChangedConvention foreignKeyPropertiesChangedConvention) + { + ForeignKeyPropertiesChangedConventions.Add(foreignKeyPropertiesChangedConvention); + } + + if (convention is IForeignKeyUniquenessChangedConvention foreignKeyUniquenessChangedConvention) + { + ForeignKeyUniquenessChangedConventions.Add(foreignKeyUniquenessChangedConvention); + } + + if (convention is IForeignKeyRequirednessChangedConvention foreignKeyRequirednessChangedConvention) + { + ForeignKeyRequirednessChangedConventions.Add(foreignKeyRequirednessChangedConvention); + } + + if (convention is IForeignKeyDependentRequirednessChangedConvention foreignKeyDependentRequirednessChangedConvention) + { + ForeignKeyDependentRequirednessChangedConventions.Add(foreignKeyDependentRequirednessChangedConvention); + } + + if (convention is IForeignKeyOwnershipChangedConvention foreignKeyOwnershipChangedConvention) + { + ForeignKeyOwnershipChangedConventions.Add(foreignKeyOwnershipChangedConvention); + } + + if (convention is IForeignKeyAnnotationChangedConvention foreignKeyAnnotationChangedConvention) + { + ForeignKeyAnnotationChangedConventions.Add(foreignKeyAnnotationChangedConvention); + } + + if (convention is IForeignKeyNullNavigationSetConvention foreignKeyNullNavigationSetConvention) + { + ForeignKeyNullNavigationSetConventions.Add(foreignKeyNullNavigationSetConvention); + } + + if (convention is INavigationAddedConvention navigationAddedConvention) + { + NavigationAddedConventions.Add(navigationAddedConvention); + } + + if (convention is INavigationAnnotationChangedConvention navigationAnnotationChangedConvention) + { + NavigationAnnotationChangedConventions.Add(navigationAnnotationChangedConvention); + } + + if (convention is INavigationRemovedConvention navigationRemovedConvention) + { + NavigationRemovedConventions.Add(navigationRemovedConvention); + } + + if (convention is ISkipNavigationAddedConvention skipNavigationAddedConvention) + { + SkipNavigationAddedConventions.Add(skipNavigationAddedConvention); + } + + if (convention is ISkipNavigationAnnotationChangedConvention skipNavigationAnnotationChangedConvention) + { + SkipNavigationAnnotationChangedConventions.Add(skipNavigationAnnotationChangedConvention); + } + + if (convention is ISkipNavigationForeignKeyChangedConvention skipNavigationForeignKeyChangedConvention) + { + SkipNavigationForeignKeyChangedConventions.Add(skipNavigationForeignKeyChangedConvention); + } + + if (convention is ISkipNavigationInverseChangedConvention skipNavigationInverseChangedConvention) + { + SkipNavigationInverseChangedConventions.Add(skipNavigationInverseChangedConvention); + } + + if (convention is ISkipNavigationRemovedConvention skipNavigationRemovedConvention) + { + SkipNavigationRemovedConventions.Add(skipNavigationRemovedConvention); + } + + if (convention is IKeyAddedConvention keyAddedConvention) + { + KeyAddedConventions.Add(keyAddedConvention); + } + + if (convention is IKeyRemovedConvention keyRemovedConvention) + { + KeyRemovedConventions.Add(keyRemovedConvention); + } + + if (convention is IKeyAnnotationChangedConvention keyAnnotationChangedConvention) + { + KeyAnnotationChangedConventions.Add(keyAnnotationChangedConvention); + } + + if (convention is IIndexAddedConvention indexAddedConvention) + { + IndexAddedConventions.Add(indexAddedConvention); + } + + if (convention is IIndexRemovedConvention indexRemovedConvention) + { + IndexRemovedConventions.Add(indexRemovedConvention); + } + + if (convention is IIndexUniquenessChangedConvention indexUniquenessChangedConvention) + { + IndexUniquenessChangedConventions.Add(indexUniquenessChangedConvention); + } + + if (convention is IIndexSortOrderChangedConvention indexSortOrderChangedConvention) + { + IndexSortOrderChangedConventions.Add(indexSortOrderChangedConvention); + } + + if (convention is IIndexAnnotationChangedConvention indexAnnotationChangedConvention) + { + IndexAnnotationChangedConventions.Add(indexAnnotationChangedConvention); + } + + if (convention is IPropertyAddedConvention propertyAddedConvention) + { + PropertyAddedConventions.Add(propertyAddedConvention); + } + + if (convention is IPropertyNullabilityChangedConvention propertyNullabilityChangedConvention) + { + PropertyNullabilityChangedConventions.Add(propertyNullabilityChangedConvention); + } + + if (convention is IPropertyFieldChangedConvention propertyFieldChangedConvention) + { + PropertyFieldChangedConventions.Add(propertyFieldChangedConvention); + } + + if (convention is IPropertyAnnotationChangedConvention propertyAnnotationChangedConvention) + { + PropertyAnnotationChangedConventions.Add(propertyAnnotationChangedConvention); + } + + if (convention is IPropertyRemovedConvention propertyRemovedConvention) + { + PropertyRemovedConventions.Add(propertyRemovedConvention); + } + } + /// /// Adds a convention before an existing convention. /// @@ -285,7 +751,7 @@ public static bool Replace( /// The type of the existing convention. /// if the convention was added. public static bool AddBefore( - IList conventionsList, + List conventionsList, TConvention newConvention, Type existingConventionType) { @@ -313,7 +779,7 @@ public static bool AddBefore( /// The type of the existing convention. /// if the convention was added. public static bool AddAfter( - IList conventionsList, + List conventionsList, TConvention newConvention, Type existingConventionType) { @@ -331,6 +797,223 @@ public static bool AddAfter( return false; } + + /// + /// Removes the convention of the given type. + /// + /// The convention type to remove. + public virtual void Remove(Type conventionType) + { + if (typeof(IModelInitializedConvention).IsAssignableFrom(conventionType)) + { + Remove(ModelInitializedConventions, conventionType); + } + + if (typeof(IModelFinalizingConvention).IsAssignableFrom(conventionType)) + { + Remove(ModelFinalizingConventions, conventionType); + } + + if (typeof(IModelFinalizedConvention).IsAssignableFrom(conventionType)) + { + Remove(ModelFinalizedConventions, conventionType); + } + + if (typeof(IModelAnnotationChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(ModelAnnotationChangedConventions, conventionType); + } + + if (typeof(IEntityTypeAddedConvention).IsAssignableFrom(conventionType)) + { + Remove(EntityTypeAddedConventions, conventionType); + } + + if (typeof(IEntityTypeIgnoredConvention).IsAssignableFrom(conventionType)) + { + Remove(EntityTypeIgnoredConventions, conventionType); + } + + if (typeof(IEntityTypeRemovedConvention).IsAssignableFrom(conventionType)) + { + Remove(EntityTypeRemovedConventions, conventionType); + } + + if (typeof(IEntityTypeMemberIgnoredConvention).IsAssignableFrom(conventionType)) + { + Remove(EntityTypeMemberIgnoredConventions, conventionType); + } + + if (typeof(IEntityTypeBaseTypeChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(EntityTypeBaseTypeChangedConventions, conventionType); + } + + if (typeof(IEntityTypePrimaryKeyChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(EntityTypePrimaryKeyChangedConventions, conventionType); + } + + if (typeof(IEntityTypeAnnotationChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(EntityTypeAnnotationChangedConventions, conventionType); + } + + if (typeof(IForeignKeyAddedConvention).IsAssignableFrom(conventionType)) + { + Remove(ForeignKeyAddedConventions, conventionType); + } + + if (typeof(IForeignKeyRemovedConvention).IsAssignableFrom(conventionType)) + { + Remove(ForeignKeyRemovedConventions, conventionType); + } + + if (typeof(IForeignKeyPrincipalEndChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(ForeignKeyPrincipalEndChangedConventions, conventionType); + } + + if (typeof(IForeignKeyPropertiesChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(ForeignKeyPropertiesChangedConventions, conventionType); + } + + if (typeof(IForeignKeyUniquenessChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(ForeignKeyUniquenessChangedConventions, conventionType); + } + + if (typeof(IForeignKeyRequirednessChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(ForeignKeyRequirednessChangedConventions, conventionType); + } + + if (typeof(IForeignKeyDependentRequirednessChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(ForeignKeyDependentRequirednessChangedConventions, conventionType); + } + + if (typeof(IForeignKeyOwnershipChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(ForeignKeyOwnershipChangedConventions, conventionType); + } + + if (typeof(IForeignKeyAnnotationChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(ForeignKeyAnnotationChangedConventions, conventionType); + } + + if (typeof(IForeignKeyNullNavigationSetConvention).IsAssignableFrom(conventionType)) + { + Remove(ForeignKeyNullNavigationSetConventions, conventionType); + } + + if (typeof(INavigationAddedConvention).IsAssignableFrom(conventionType)) + { + Remove(NavigationAddedConventions, conventionType); + } + + if (typeof(INavigationAnnotationChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(NavigationAnnotationChangedConventions, conventionType); + } + + if (typeof(INavigationRemovedConvention).IsAssignableFrom(conventionType)) + { + Remove(NavigationRemovedConventions, conventionType); + } + + if (typeof(ISkipNavigationAddedConvention).IsAssignableFrom(conventionType)) + { + Remove(SkipNavigationAddedConventions, conventionType); + } + + if (typeof(ISkipNavigationAnnotationChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(SkipNavigationAnnotationChangedConventions, conventionType); + } + + if (typeof(ISkipNavigationForeignKeyChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(SkipNavigationForeignKeyChangedConventions, conventionType); + } + + if (typeof(ISkipNavigationInverseChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(SkipNavigationInverseChangedConventions, conventionType); + } + + if (typeof(ISkipNavigationRemovedConvention).IsAssignableFrom(conventionType)) + { + Remove(SkipNavigationRemovedConventions, conventionType); + } + + if (typeof(IKeyAddedConvention).IsAssignableFrom(conventionType)) + { + Remove(KeyAddedConventions, conventionType); + } + + if (typeof(IKeyRemovedConvention).IsAssignableFrom(conventionType)) + { + Remove(KeyRemovedConventions, conventionType); + } + + if (typeof(IKeyAnnotationChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(KeyAnnotationChangedConventions, conventionType); + } + + if (typeof(IIndexAddedConvention).IsAssignableFrom(conventionType)) + { + Remove(IndexAddedConventions, conventionType); + } + + if (typeof(IIndexRemovedConvention).IsAssignableFrom(conventionType)) + { + Remove(IndexRemovedConventions, conventionType); + } + + if (typeof(IIndexUniquenessChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(IndexUniquenessChangedConventions, conventionType); + } + + if (typeof(IIndexSortOrderChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(IndexSortOrderChangedConventions, conventionType); + } + + if (typeof(IIndexAnnotationChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(IndexAnnotationChangedConventions, conventionType); + } + + if (typeof(IPropertyAddedConvention).IsAssignableFrom(conventionType)) + { + Remove(PropertyAddedConventions, conventionType); + } + + if (typeof(IPropertyNullabilityChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(PropertyNullabilityChangedConventions, conventionType); + } + + if (typeof(IPropertyFieldChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(PropertyFieldChangedConventions, conventionType); + } + + if (typeof(IPropertyAnnotationChangedConvention).IsAssignableFrom(conventionType)) + { + Remove(PropertyAnnotationChangedConventions, conventionType); + } + + if (typeof(IPropertyRemovedConvention).IsAssignableFrom(conventionType)) + { + Remove(PropertyRemovedConventions, conventionType); + } + } /// /// Removes an existing convention. @@ -340,7 +1023,7 @@ public static bool AddAfter( /// The type of the existing convention. /// if the convention was removed. public static bool Remove( - IList conventionsList, + List conventionsList, Type existingConventionType) { Check.NotNull(conventionsList, nameof(conventionsList)); diff --git a/src/EFCore/Metadata/Conventions/IndexAttributeConvention.cs b/src/EFCore/Metadata/Conventions/IndexAttributeConvention.cs index e1acf29c34a..8389eab049d 100644 --- a/src/EFCore/Metadata/Conventions/IndexAttributeConvention.cs +++ b/src/EFCore/Metadata/Conventions/IndexAttributeConvention.cs @@ -9,7 +9,10 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions; /// /// See Model building conventions for more information and examples. /// -public class IndexAttributeConvention : IEntityTypeAddedConvention, IEntityTypeBaseTypeChangedConvention, IModelFinalizingConvention +public class IndexAttributeConvention : + IEntityTypeAddedConvention, + IEntityTypeBaseTypeChangedConvention, + IModelFinalizingConvention { /// /// Creates a new instance of . @@ -65,45 +68,25 @@ private static void CheckIndexAttributesAndEnsureIndex( entityType.ClrType.GetCustomAttributes(inherit: true)) { IConventionIndexBuilder? indexBuilder; - if (!shouldThrow) + if (!shouldThrow + && !entityType.Builder.CanHaveIndex(indexAttribute.PropertyNames, fromDataAnnotation: true)) { - var indexProperties = new List(); - foreach (var propertyName in indexAttribute.PropertyNames) - { - var property = entityType.FindProperty(propertyName); - if (property == null) - { - return; - } - - indexProperties.Add(property); - } + continue; + } + try + { indexBuilder = indexAttribute.Name == null ? entityType.Builder.HasIndex( - indexProperties, fromDataAnnotation: true) + indexAttribute.PropertyNames, fromDataAnnotation: true) : entityType.Builder.HasIndex( - indexProperties, indexAttribute.Name, fromDataAnnotation: true); + indexAttribute.PropertyNames, indexAttribute.Name, fromDataAnnotation: true); } - else + catch (InvalidOperationException exception) { - try - { - // Using the HasIndex(propertyNames) overload gives us - // a chance to create a missing property - // e.g. if the CLR property existed but was non-public. - indexBuilder = indexAttribute.Name == null - ? entityType.Builder.HasIndex( - indexAttribute.PropertyNames, fromDataAnnotation: true) - : entityType.Builder.HasIndex( - indexAttribute.PropertyNames, indexAttribute.Name, fromDataAnnotation: true); - } - catch (InvalidOperationException exception) - { - CheckMissingProperties(entityType, indexAttribute, exception); + CheckMissingProperties(entityType, indexAttribute, exception); - throw; - } + throw; } if (indexBuilder == null) diff --git a/src/EFCore/Metadata/Conventions/Infrastructure/ProviderConventionSetBuilder.cs b/src/EFCore/Metadata/Conventions/Infrastructure/ProviderConventionSetBuilder.cs index 3b934a7f0fd..d9f5fd95ca4 100644 --- a/src/EFCore/Metadata/Conventions/Infrastructure/ProviderConventionSetBuilder.cs +++ b/src/EFCore/Metadata/Conventions/Infrastructure/ProviderConventionSetBuilder.cs @@ -53,201 +53,49 @@ public ProviderConventionSetBuilder(ProviderConventionSetBuilderDependencies dep public virtual ConventionSet CreateConventionSet() { var conventionSet = new ConventionSet(); - - var propertyDiscoveryConvention = new PropertyDiscoveryConvention(Dependencies); - var keyDiscoveryConvention = new KeyDiscoveryConvention(Dependencies); - var inversePropertyAttributeConvention = new InversePropertyAttributeConvention(Dependencies); - var foreignKeyAttributeConvention = new ForeignKeyAttributeConvention(Dependencies); - var relationshipDiscoveryConvention = new RelationshipDiscoveryConvention(Dependencies); - var servicePropertyDiscoveryConvention = new ServicePropertyDiscoveryConvention(Dependencies); - var keyAttributeConvention = new KeyAttributeConvention(Dependencies); - var indexAttributeConvention = new IndexAttributeConvention(Dependencies); - var baseTypeDiscoveryConvention = new BaseTypeDiscoveryConvention(Dependencies); - conventionSet.EntityTypeAddedConventions.Add(new NotMappedEntityTypeAttributeConvention(Dependencies)); - conventionSet.EntityTypeAddedConventions.Add(new OwnedEntityTypeAttributeConvention(Dependencies)); - conventionSet.EntityTypeAddedConventions.Add(new KeylessEntityTypeAttributeConvention(Dependencies)); - conventionSet.EntityTypeAddedConventions.Add(new EntityTypeConfigurationEntityTypeAttributeConvention(Dependencies)); - conventionSet.EntityTypeAddedConventions.Add(new NotMappedMemberAttributeConvention(Dependencies)); - conventionSet.EntityTypeAddedConventions.Add(baseTypeDiscoveryConvention); - conventionSet.EntityTypeAddedConventions.Add(propertyDiscoveryConvention); - conventionSet.EntityTypeAddedConventions.Add(servicePropertyDiscoveryConvention); - conventionSet.EntityTypeAddedConventions.Add(keyAttributeConvention); - conventionSet.EntityTypeAddedConventions.Add(keyDiscoveryConvention); - conventionSet.EntityTypeAddedConventions.Add(indexAttributeConvention); - conventionSet.EntityTypeAddedConventions.Add(inversePropertyAttributeConvention); - conventionSet.EntityTypeAddedConventions.Add(foreignKeyAttributeConvention); - conventionSet.EntityTypeAddedConventions.Add(relationshipDiscoveryConvention); - - conventionSet.EntityTypeIgnoredConventions.Add(relationshipDiscoveryConvention); - - var discriminatorConvention = new DiscriminatorConvention(Dependencies); - conventionSet.EntityTypeRemovedConventions.Add(inversePropertyAttributeConvention); - conventionSet.EntityTypeRemovedConventions.Add(discriminatorConvention); - - var foreignKeyIndexConvention = new ForeignKeyIndexConvention(Dependencies); - var valueGeneratorConvention = new ValueGenerationConvention(Dependencies); - - conventionSet.EntityTypeBaseTypeChangedConventions.Add(propertyDiscoveryConvention); - conventionSet.EntityTypeBaseTypeChangedConventions.Add(servicePropertyDiscoveryConvention); - conventionSet.EntityTypeBaseTypeChangedConventions.Add(keyAttributeConvention); - conventionSet.EntityTypeBaseTypeChangedConventions.Add(keyDiscoveryConvention); - conventionSet.EntityTypeBaseTypeChangedConventions.Add(indexAttributeConvention); - conventionSet.EntityTypeBaseTypeChangedConventions.Add(inversePropertyAttributeConvention); - conventionSet.EntityTypeBaseTypeChangedConventions.Add(relationshipDiscoveryConvention); - conventionSet.EntityTypeBaseTypeChangedConventions.Add(foreignKeyIndexConvention); - conventionSet.EntityTypeBaseTypeChangedConventions.Add(valueGeneratorConvention); - conventionSet.EntityTypeBaseTypeChangedConventions.Add(discriminatorConvention); - - var foreignKeyPropertyDiscoveryConvention = new ForeignKeyPropertyDiscoveryConvention(Dependencies); - - conventionSet.EntityTypeMemberIgnoredConventions.Add(inversePropertyAttributeConvention); - conventionSet.EntityTypeMemberIgnoredConventions.Add(relationshipDiscoveryConvention); - conventionSet.EntityTypeMemberIgnoredConventions.Add(keyDiscoveryConvention); - conventionSet.EntityTypeMemberIgnoredConventions.Add(foreignKeyPropertyDiscoveryConvention); - - var backingFieldConvention = new BackingFieldConvention(Dependencies); - var concurrencyCheckAttributeConvention = new ConcurrencyCheckAttributeConvention(Dependencies); - var databaseGeneratedAttributeConvention = new DatabaseGeneratedAttributeConvention(Dependencies); - var requiredPropertyAttributeConvention = new RequiredPropertyAttributeConvention(Dependencies); - var nonNullableReferencePropertyConvention = new NonNullableReferencePropertyConvention(Dependencies); - var maxLengthAttributeConvention = new MaxLengthAttributeConvention(Dependencies); - var stringLengthAttributeConvention = new StringLengthAttributeConvention(Dependencies); - var timestampAttributeConvention = new TimestampAttributeConvention(Dependencies); - var backingFieldAttributeConvention = new BackingFieldAttributeConvention(Dependencies); - var unicodeAttributeConvention = new UnicodeAttributeConvention(Dependencies); - var precisionAttributeConvention = new PrecisionAttributeConvention(Dependencies); - var deleteBehaviorAttributeConvention = new DeleteBehaviorAttributeConvention(Dependencies); - - conventionSet.PropertyAddedConventions.Add(backingFieldAttributeConvention); - conventionSet.PropertyAddedConventions.Add(backingFieldConvention); - conventionSet.PropertyAddedConventions.Add(concurrencyCheckAttributeConvention); - conventionSet.PropertyAddedConventions.Add(databaseGeneratedAttributeConvention); - conventionSet.PropertyAddedConventions.Add(requiredPropertyAttributeConvention); - conventionSet.PropertyAddedConventions.Add(nonNullableReferencePropertyConvention); - conventionSet.PropertyAddedConventions.Add(maxLengthAttributeConvention); - conventionSet.PropertyAddedConventions.Add(stringLengthAttributeConvention); - conventionSet.PropertyAddedConventions.Add(timestampAttributeConvention); - conventionSet.PropertyAddedConventions.Add(keyAttributeConvention); - conventionSet.PropertyAddedConventions.Add(keyDiscoveryConvention); - conventionSet.PropertyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention); - conventionSet.PropertyAddedConventions.Add(unicodeAttributeConvention); - conventionSet.PropertyAddedConventions.Add(precisionAttributeConvention); - conventionSet.PropertyAddedConventions.Add(deleteBehaviorAttributeConvention); - - conventionSet.EntityTypePrimaryKeyChangedConventions.Add(foreignKeyPropertyDiscoveryConvention); - conventionSet.EntityTypePrimaryKeyChangedConventions.Add(valueGeneratorConvention); - - conventionSet.KeyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention); - conventionSet.KeyAddedConventions.Add(foreignKeyIndexConvention); - - conventionSet.KeyRemovedConventions.Add(foreignKeyPropertyDiscoveryConvention); - conventionSet.KeyRemovedConventions.Add(foreignKeyIndexConvention); - conventionSet.KeyRemovedConventions.Add(keyDiscoveryConvention); - - var cascadeDeleteConvention = new CascadeDeleteConvention(Dependencies); - - conventionSet.ForeignKeyAddedConventions.Add(foreignKeyAttributeConvention); - conventionSet.ForeignKeyAddedConventions.Add(foreignKeyPropertyDiscoveryConvention); - conventionSet.ForeignKeyAddedConventions.Add(keyDiscoveryConvention); - conventionSet.ForeignKeyAddedConventions.Add(valueGeneratorConvention); - conventionSet.ForeignKeyAddedConventions.Add(cascadeDeleteConvention); - conventionSet.ForeignKeyAddedConventions.Add(foreignKeyIndexConvention); - - conventionSet.ForeignKeyRemovedConventions.Add(baseTypeDiscoveryConvention); - conventionSet.ForeignKeyRemovedConventions.Add(relationshipDiscoveryConvention); - conventionSet.ForeignKeyRemovedConventions.Add(keyDiscoveryConvention); - conventionSet.ForeignKeyRemovedConventions.Add(valueGeneratorConvention); - conventionSet.ForeignKeyRemovedConventions.Add(foreignKeyIndexConvention); - - conventionSet.ForeignKeyPropertiesChangedConventions.Add(foreignKeyPropertyDiscoveryConvention); - conventionSet.ForeignKeyPropertiesChangedConventions.Add(keyDiscoveryConvention); - conventionSet.ForeignKeyPropertiesChangedConventions.Add(valueGeneratorConvention); - conventionSet.ForeignKeyPropertiesChangedConventions.Add(foreignKeyIndexConvention); - - conventionSet.ForeignKeyUniquenessChangedConventions.Add(foreignKeyPropertyDiscoveryConvention); - conventionSet.ForeignKeyUniquenessChangedConventions.Add(keyDiscoveryConvention); - conventionSet.ForeignKeyUniquenessChangedConventions.Add(foreignKeyIndexConvention); - - conventionSet.ForeignKeyRequirednessChangedConventions.Add(cascadeDeleteConvention); - conventionSet.ForeignKeyRequirednessChangedConventions.Add(foreignKeyPropertyDiscoveryConvention); - - conventionSet.ForeignKeyOwnershipChangedConventions.Add(new NavigationEagerLoadingConvention(Dependencies)); - conventionSet.ForeignKeyOwnershipChangedConventions.Add(relationshipDiscoveryConvention); - conventionSet.ForeignKeyOwnershipChangedConventions.Add(keyDiscoveryConvention); - conventionSet.ForeignKeyOwnershipChangedConventions.Add(valueGeneratorConvention); - - conventionSet.ForeignKeyNullNavigationSetConventions.Add(relationshipDiscoveryConvention); - - var requiredNavigationAttributeConvention = new RequiredNavigationAttributeConvention(Dependencies); - var nonNullableNavigationConvention = new NonNullableNavigationConvention(Dependencies); - conventionSet.NavigationAddedConventions.Add(new NavigationBackingFieldAttributeConvention(Dependencies)); - conventionSet.NavigationAddedConventions.Add(backingFieldConvention); - conventionSet.NavigationAddedConventions.Add(requiredNavigationAttributeConvention); - conventionSet.NavigationAddedConventions.Add(nonNullableNavigationConvention); - conventionSet.NavigationAddedConventions.Add(inversePropertyAttributeConvention); - conventionSet.NavigationAddedConventions.Add(foreignKeyPropertyDiscoveryConvention); - conventionSet.NavigationAddedConventions.Add(relationshipDiscoveryConvention); - conventionSet.NavigationAddedConventions.Add(foreignKeyAttributeConvention); - conventionSet.NavigationAddedConventions.Add(deleteBehaviorAttributeConvention); - - var manyToManyJoinEntityTypeConvention = new ManyToManyJoinEntityTypeConvention(Dependencies); - conventionSet.SkipNavigationAddedConventions.Add(new NavigationBackingFieldAttributeConvention(Dependencies)); - conventionSet.SkipNavigationAddedConventions.Add(backingFieldConvention); - conventionSet.SkipNavigationAddedConventions.Add(manyToManyJoinEntityTypeConvention); - - conventionSet.SkipNavigationRemovedConventions.Add(manyToManyJoinEntityTypeConvention); - - conventionSet.SkipNavigationInverseChangedConventions.Add(manyToManyJoinEntityTypeConvention); - conventionSet.SkipNavigationInverseChangedConventions.Add(foreignKeyPropertyDiscoveryConvention); - - conventionSet.SkipNavigationForeignKeyChangedConventions.Add(manyToManyJoinEntityTypeConvention); - conventionSet.SkipNavigationForeignKeyChangedConventions.Add(foreignKeyAttributeConvention); - conventionSet.SkipNavigationForeignKeyChangedConventions.Add(keyDiscoveryConvention); - conventionSet.SkipNavigationForeignKeyChangedConventions.Add(foreignKeyPropertyDiscoveryConvention); - - conventionSet.NavigationRemovedConventions.Add(relationshipDiscoveryConvention); - - conventionSet.IndexAddedConventions.Add(foreignKeyIndexConvention); - - conventionSet.IndexRemovedConventions.Add(foreignKeyIndexConvention); - - conventionSet.IndexUniquenessChangedConventions.Add(foreignKeyIndexConvention); - - conventionSet.ForeignKeyPrincipalEndChangedConventions.Add(foreignKeyPropertyDiscoveryConvention); - conventionSet.ForeignKeyPrincipalEndChangedConventions.Add(requiredNavigationAttributeConvention); - conventionSet.ForeignKeyPrincipalEndChangedConventions.Add(nonNullableNavigationConvention); - conventionSet.ForeignKeyPrincipalEndChangedConventions.Add(deleteBehaviorAttributeConvention); - - conventionSet.PropertyNullabilityChangedConventions.Add(foreignKeyPropertyDiscoveryConvention); - - conventionSet.PropertyFieldChangedConventions.Add(foreignKeyPropertyDiscoveryConvention); - conventionSet.PropertyFieldChangedConventions.Add(keyAttributeConvention); - conventionSet.PropertyFieldChangedConventions.Add(concurrencyCheckAttributeConvention); - conventionSet.PropertyFieldChangedConventions.Add(databaseGeneratedAttributeConvention); - conventionSet.PropertyFieldChangedConventions.Add(requiredPropertyAttributeConvention); - conventionSet.PropertyFieldChangedConventions.Add(nonNullableReferencePropertyConvention); - conventionSet.PropertyFieldChangedConventions.Add(maxLengthAttributeConvention); - conventionSet.PropertyFieldChangedConventions.Add(stringLengthAttributeConvention); - conventionSet.PropertyFieldChangedConventions.Add(timestampAttributeConvention); - - conventionSet.ModelInitializedConventions.Add(new DbSetFindingConvention(Dependencies)); - - conventionSet.ModelFinalizingConventions.Add(new ModelCleanupConvention(Dependencies)); - conventionSet.ModelFinalizingConventions.Add(keyAttributeConvention); - conventionSet.ModelFinalizingConventions.Add(indexAttributeConvention); - conventionSet.ModelFinalizingConventions.Add(foreignKeyAttributeConvention); - conventionSet.ModelFinalizingConventions.Add(new ChangeTrackingStrategyConvention(Dependencies)); - conventionSet.ModelFinalizingConventions.Add(new ConstructorBindingConvention(Dependencies)); - conventionSet.ModelFinalizingConventions.Add(foreignKeyIndexConvention); - conventionSet.ModelFinalizingConventions.Add(foreignKeyPropertyDiscoveryConvention); - conventionSet.ModelFinalizingConventions.Add(nonNullableReferencePropertyConvention); - conventionSet.ModelFinalizingConventions.Add(nonNullableNavigationConvention); - conventionSet.ModelFinalizingConventions.Add(new QueryFilterRewritingConvention(Dependencies)); - conventionSet.ModelFinalizingConventions.Add(inversePropertyAttributeConvention); - conventionSet.ModelFinalizingConventions.Add(backingFieldConvention); - conventionSet.ModelFinalizingConventions.Add(deleteBehaviorAttributeConvention); - - conventionSet.ModelFinalizedConventions.Add(new RuntimeModelConvention(Dependencies)); + + conventionSet.Add(new ModelCleanupConvention(Dependencies)); + conventionSet.Add(new NotMappedEntityTypeAttributeConvention(Dependencies)); + conventionSet.Add(new OwnedEntityTypeAttributeConvention(Dependencies)); + conventionSet.Add(new KeylessEntityTypeAttributeConvention(Dependencies)); + conventionSet.Add(new EntityTypeConfigurationEntityTypeAttributeConvention(Dependencies)); + conventionSet.Add(new NotMappedMemberAttributeConvention(Dependencies)); + conventionSet.Add(new BackingFieldAttributeConvention(Dependencies)); + conventionSet.Add(new ConcurrencyCheckAttributeConvention(Dependencies)); + conventionSet.Add(new DatabaseGeneratedAttributeConvention(Dependencies)); + conventionSet.Add(new RequiredPropertyAttributeConvention(Dependencies)); + conventionSet.Add(new MaxLengthAttributeConvention(Dependencies)); + conventionSet.Add(new StringLengthAttributeConvention(Dependencies)); + conventionSet.Add(new TimestampAttributeConvention(Dependencies)); + conventionSet.Add(new ForeignKeyAttributeConvention(Dependencies)); + conventionSet.Add(new UnicodeAttributeConvention(Dependencies)); + conventionSet.Add(new PrecisionAttributeConvention(Dependencies)); + conventionSet.Add(new InversePropertyAttributeConvention(Dependencies)); + conventionSet.Add(new DeleteBehaviorAttributeConvention(Dependencies)); + conventionSet.Add(new NavigationBackingFieldAttributeConvention(Dependencies)); + conventionSet.Add(new NavigationEagerLoadingConvention(Dependencies)); + conventionSet.Add(new RequiredNavigationAttributeConvention(Dependencies)); + conventionSet.Add(new DbSetFindingConvention(Dependencies)); + conventionSet.Add(new BaseTypeDiscoveryConvention(Dependencies)); + conventionSet.Add(new ManyToManyJoinEntityTypeConvention(Dependencies)); + conventionSet.Add(new PropertyDiscoveryConvention(Dependencies)); + conventionSet.Add(new KeyDiscoveryConvention(Dependencies)); + conventionSet.Add(new ServicePropertyDiscoveryConvention(Dependencies)); + conventionSet.Add(new RelationshipDiscoveryConvention(Dependencies)); + conventionSet.Add(new ValueGenerationConvention(Dependencies)); + conventionSet.Add(new DiscriminatorConvention(Dependencies)); + conventionSet.Add(new CascadeDeleteConvention(Dependencies)); + conventionSet.Add(new ChangeTrackingStrategyConvention(Dependencies)); + conventionSet.Add(new ConstructorBindingConvention(Dependencies)); + conventionSet.Add(new KeyAttributeConvention(Dependencies)); + conventionSet.Add(new IndexAttributeConvention(Dependencies)); + conventionSet.Add(new ForeignKeyIndexConvention(Dependencies)); + conventionSet.Add(new ForeignKeyPropertyDiscoveryConvention(Dependencies)); + conventionSet.Add(new NonNullableReferencePropertyConvention(Dependencies)); + conventionSet.Add(new NonNullableNavigationConvention(Dependencies)); + conventionSet.Add(new BackingFieldConvention(Dependencies)); + conventionSet.Add(new QueryFilterRewritingConvention(Dependencies)); + conventionSet.Add(new RuntimeModelConvention(Dependencies)); return conventionSet; } @@ -260,7 +108,7 @@ public virtual ConventionSet CreateConventionSet() /// The list of existing convention instances to scan. /// The new convention. protected virtual bool ReplaceConvention( - IList conventionsList, + List conventionsList, TImplementation newConvention) where TImplementation : TConvention => ConventionSet.Replace(conventionsList, newConvention); diff --git a/src/EFCore/Metadata/Conventions/InversePropertyAttributeConvention.cs b/src/EFCore/Metadata/Conventions/InversePropertyAttributeConvention.cs index c08ac46a019..fdafce4b4e4 100644 --- a/src/EFCore/Metadata/Conventions/InversePropertyAttributeConvention.cs +++ b/src/EFCore/Metadata/Conventions/InversePropertyAttributeConvention.cs @@ -15,6 +15,11 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions; /// public class InversePropertyAttributeConvention : NavigationAttributeConventionBase, + IEntityTypeAddedConvention, + IEntityTypeRemovedConvention, + IEntityTypeBaseTypeChangedConvention, + IEntityTypeMemberIgnoredConvention, + INavigationAddedConvention, IModelFinalizingConvention { /// diff --git a/src/EFCore/Metadata/Conventions/KeyAttributeConvention.cs b/src/EFCore/Metadata/Conventions/KeyAttributeConvention.cs index f1c3831a2ba..f2c24e473a7 100644 --- a/src/EFCore/Metadata/Conventions/KeyAttributeConvention.cs +++ b/src/EFCore/Metadata/Conventions/KeyAttributeConvention.cs @@ -183,36 +183,21 @@ private static bool CheckPrimaryKeyAttributeAndEnsurePrimaryKey( } IConventionKeyBuilder? keyBuilder; - if (!shouldThrow) + if (!shouldThrow + && !entityType.Builder.CanSetPrimaryKey(primaryKeyAttribute.PropertyNames, fromDataAnnotation: true)) { - var keyProperties = new List(); - foreach (var propertyName in primaryKeyAttribute.PropertyNames) - { - var property = entityType.FindProperty(propertyName); - if (property == null) - { - return true; - } - - keyProperties.Add(property); - } + return true; + } - keyBuilder = entityType.Builder.PrimaryKey(keyProperties, fromDataAnnotation: true); + try + { + keyBuilder = entityType.Builder.PrimaryKey(primaryKeyAttribute.PropertyNames, fromDataAnnotation: true); } - else + catch (InvalidOperationException exception) { - try - { - // Using the PrimaryKey(propertyNames) overload gives us a chance to create a missing property - // e.g. if the CLR property existed but was non-public. - keyBuilder = entityType.Builder.PrimaryKey(primaryKeyAttribute.PropertyNames, fromDataAnnotation: true); - } - catch (InvalidOperationException exception) - { - CheckMissingProperties(entityType, primaryKeyAttribute, exception); + CheckMissingProperties(entityType, primaryKeyAttribute, exception); - throw; - } + throw; } if (keyBuilder == null diff --git a/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs index 8ccbd607313..3325988dcbd 100644 --- a/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs +++ b/src/EFCore/Metadata/Conventions/KeyDiscoveryConvention.cs @@ -59,7 +59,7 @@ protected virtual void TryConfigurePrimaryKey(IConventionEntityTypeBuilder entit var entityType = entityTypeBuilder.Metadata; if (entityType.BaseType != null || (entityType.IsKeyless && entityType.GetIsKeylessConfigurationSource() != ConfigurationSource.Convention) - || !entityTypeBuilder.CanSetPrimaryKey(null)) + || !entityTypeBuilder.CanSetPrimaryKey((IReadOnlyList?)null)) { return; } diff --git a/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs b/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs index e4e7b7e1143..d5f043b075d 100644 --- a/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs +++ b/src/EFCore/Metadata/Conventions/NavigationAttributeConventionBase.cs @@ -13,15 +13,7 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions; /// See Model building conventions for more information and examples. /// /// The attribute type to look for. -public abstract class NavigationAttributeConventionBase : - IEntityTypeAddedConvention, - IEntityTypeIgnoredConvention, - IEntityTypeRemovedConvention, - IEntityTypeBaseTypeChangedConvention, - IEntityTypeMemberIgnoredConvention, - INavigationAddedConvention, - ISkipNavigationAddedConvention, - IForeignKeyPrincipalEndChangedConvention +public abstract class NavigationAttributeConventionBase where TAttribute : Attribute { /// @@ -37,8 +29,12 @@ protected NavigationAttributeConventionBase(ProviderConventionSetBuilderDependen /// Dependencies for this service. /// protected virtual ProviderConventionSetBuilderDependencies Dependencies { get; } - - /// + + /// + /// Called after an entity type is added to the model. + /// + /// The builder for the entity type. + /// Additional information associated with convention execution. public virtual void ProcessEntityTypeAdded( IConventionEntityTypeBuilder entityTypeBuilder, IConventionContext context) @@ -63,8 +59,14 @@ public virtual void ProcessEntityTypeAdded( } } } - - /// + + /// + /// Called after an entity type is ignored. + /// + /// The builder for the model. + /// The name of the ignored entity type. + /// The ignored entity type. + /// Additional information associated with convention execution. public virtual void ProcessEntityTypeIgnored( IConventionModelBuilder modelBuilder, string name, @@ -109,8 +111,13 @@ public virtual void ProcessEntityTypeIgnored( } } } - - /// + + /// + /// Called after an entity type is removed from the model. + /// + /// The builder for the model. + /// The removed entity type. + /// Additional information associated with convention execution. public virtual void ProcessEntityTypeRemoved( IConventionModelBuilder modelBuilder, IConventionEntityType entityType, @@ -136,8 +143,14 @@ public virtual void ProcessEntityTypeRemoved( } } } - - /// + + /// + /// Called after the base type of an entity type changes. + /// + /// The builder for the entity type. + /// The new base entity type. + /// The old base entity type. + /// Additional information associated with convention execution. public virtual void ProcessEntityTypeBaseTypeChanged( IConventionEntityTypeBuilder entityTypeBuilder, IConventionEntityType? newBaseType, @@ -198,8 +211,12 @@ public virtual void ProcessEntityTypeBaseTypeChanged( private static void Sort(List<(PropertyInfo, Type)> navigations) => navigations.Sort((x, y) => StringComparer.Ordinal.Compare(x.Item1.Name, y.Item1.Name)); - - /// + + /// + /// Called after a navigation is added to the entity type. + /// + /// The builder for the navigation. + /// Additional information associated with convention execution. public virtual void ProcessNavigationAdded( IConventionNavigationBuilder navigationBuilder, IConventionContext context) @@ -215,8 +232,12 @@ public virtual void ProcessNavigationAdded( } } } - - /// + + /// + /// Called after a skip navigation is added to the entity type. + /// + /// The builder for the skip navigation. + /// Additional information associated with convention execution. public virtual void ProcessSkipNavigationAdded( IConventionSkipNavigationBuilder skipNavigationBuilder, IConventionContext context) @@ -232,8 +253,12 @@ public virtual void ProcessSkipNavigationAdded( } } } - - /// + + /// + /// Called after the principal end of a foreign key is changed. + /// + /// The builder for the foreign key. + /// Additional information associated with convention execution. public virtual void ProcessForeignKeyPrincipalEndChanged( IConventionForeignKeyBuilder relationshipBuilder, IConventionContext context) @@ -248,8 +273,13 @@ public virtual void ProcessForeignKeyPrincipalEndChanged( ProcessForeignKeyPrincipalEndChanged( relationshipBuilder, dependentToPrincipalAttributes, principalToDependentAttributes, context); } - - /// + + /// + /// Called after an entity type member is ignored. + /// + /// The builder for the entity type. + /// The name of the ignored member. + /// Additional information associated with convention execution. public virtual void ProcessEntityTypeMemberIgnored( IConventionEntityTypeBuilder entityTypeBuilder, string name, diff --git a/src/EFCore/Metadata/Conventions/NavigationBackingFieldAttributeConvention.cs b/src/EFCore/Metadata/Conventions/NavigationBackingFieldAttributeConvention.cs index ffa5b07bb8d..078963f2a99 100644 --- a/src/EFCore/Metadata/Conventions/NavigationBackingFieldAttributeConvention.cs +++ b/src/EFCore/Metadata/Conventions/NavigationBackingFieldAttributeConvention.cs @@ -10,7 +10,10 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions; /// /// See Model building conventions for more information and examples. /// -public class NavigationBackingFieldAttributeConvention : NavigationAttributeConventionBase +public class NavigationBackingFieldAttributeConvention : + NavigationAttributeConventionBase, + INavigationAddedConvention, + ISkipNavigationAddedConvention { /// /// Creates a new instance of . diff --git a/src/EFCore/Metadata/Conventions/RequiredNavigationAttributeConvention.cs b/src/EFCore/Metadata/Conventions/RequiredNavigationAttributeConvention.cs index f22e3caa790..2a1384b1bda 100644 --- a/src/EFCore/Metadata/Conventions/RequiredNavigationAttributeConvention.cs +++ b/src/EFCore/Metadata/Conventions/RequiredNavigationAttributeConvention.cs @@ -12,7 +12,11 @@ namespace Microsoft.EntityFrameworkCore.Metadata.Conventions; /// /// See Model building conventions for more information and examples. /// -public class RequiredNavigationAttributeConvention : NavigationAttributeConventionBase +public class RequiredNavigationAttributeConvention : + NavigationAttributeConventionBase, + INavigationAddedConvention, + ISkipNavigationAddedConvention, + IForeignKeyPrincipalEndChangedConvention { /// /// Creates a new instance of . diff --git a/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs b/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs index 5978cfcd461..b585ca277f7 100644 --- a/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalEntityTypeBuilder.cs @@ -148,6 +148,42 @@ public InternalEntityTypeBuilder(EntityType metadata, InternalModelBuilder model return keyBuilder; } + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual bool CanSetPrimaryKey( + IReadOnlyList propertyNames, + ConfigurationSource configurationSource) + { + for (var i = 0; i < propertyNames.Count; i++) + { + if (!CanHaveProperty( + propertyType: null, + propertyNames[i], + null, + typeConfigurationSource: null, + configurationSource, + checkClrProperty: true)) + { + return false; + } + } + + var previousPrimaryKey = Metadata.FindPrimaryKey(); + if (previousPrimaryKey != null + && previousPrimaryKey.Properties.Select(p => p.Name).SequenceEqual(propertyNames)) + { + return true; + } + + return configurationSource.Overrides(Metadata.GetPrimaryKeyConfigurationSource()) + && (!Metadata.IsKeyless + || configurationSource.Overrides(Metadata.GetIsKeylessConfigurationSource())); + } /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -674,7 +710,8 @@ public virtual bool CanHaveProperty( string propertyName, MemberInfo? memberInfo, ConfigurationSource? typeConfigurationSource, - ConfigurationSource? configurationSource) + ConfigurationSource? configurationSource, + bool checkClrProperty = false) { var existingProperty = Metadata.FindProperty(propertyName); return existingProperty != null @@ -686,16 +723,20 @@ public virtual bool CanHaveProperty( || typeConfigurationSource.Overrides(existingTypeConfigurationSource))) || configurationSource.Overrides(existingProperty.GetConfigurationSource()) : configurationSource.HasValue - && CanAddProperty(propertyType ?? memberInfo?.GetMemberType(), propertyName, configurationSource.Value); + && CanAddProperty(propertyType ?? memberInfo?.GetMemberType(), propertyName, configurationSource.Value, checkClrProperty); } private bool CanAddProperty( Type? propertyType, string propertyName, - ConfigurationSource configurationSource) + ConfigurationSource configurationSource, + bool checkClrProperty = false) => !IsIgnored(propertyName, configurationSource) && (propertyType == null || Metadata.Model.Builder.CanBeConfigured(propertyType, TypeConfigurationType.Property, configurationSource)) + && (!checkClrProperty + || propertyType != null + || Metadata.GetRuntimeProperties().ContainsKey(propertyName)) && Metadata.FindServicePropertiesInHierarchy(propertyName).Cast() .Concat(Metadata.FindNavigationsInHierarchy(propertyName)) .Concat(Metadata.FindSkipNavigationsInHierarchy(propertyName)) @@ -2425,6 +2466,33 @@ private static void RemovePropertyIfUnused(Property property, ConfigurationSourc return index?.Builder; } + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public virtual bool CanHaveIndex( + IReadOnlyList propertyNames, + ConfigurationSource configurationSource) + { + for (var i = 0; i < propertyNames.Count; i++) + { + if (!CanHaveProperty( + propertyType: null, + propertyNames[i], + null, + typeConfigurationSource: null, + configurationSource, + checkClrProperty: true)) + { + return false; + } + } + + return true; + } + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -5236,6 +5304,18 @@ bool IConventionEntityTypeBuilder.CanIgnore(string name, bool fromDataAnnotation properties as IReadOnlyList ?? properties?.Cast().ToList(), fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention); + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [DebuggerStepThrough] + bool IConventionEntityTypeBuilder.CanSetPrimaryKey(IReadOnlyList propertyNames, bool fromDataAnnotation) + => CanSetPrimaryKey( + propertyNames, + fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention); + /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -5348,6 +5428,18 @@ bool IConventionEntityTypeBuilder.CanRemoveKey(bool fromDataAnnotation) propertyNames, name, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention); + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + [DebuggerStepThrough] + bool IConventionEntityTypeBuilder.CanHaveIndex(IReadOnlyList propertyNames, bool fromDataAnnotation) + => CanHaveIndex( + propertyNames, + fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/test/EFCore.Tests/Metadata/Conventions/ConventionSetBuilderTests.cs b/test/EFCore.Tests/Metadata/Conventions/ConventionSetBuilderTests.cs index 947d97500ee..01083a2fdaf 100644 --- a/test/EFCore.Tests/Metadata/Conventions/ConventionSetBuilderTests.cs +++ b/test/EFCore.Tests/Metadata/Conventions/ConventionSetBuilderTests.cs @@ -33,6 +33,46 @@ public virtual IReadOnlyModel Can_build_a_model_with_default_conventions_without return model; } + [ConditionalFact] + public virtual void Can_add_remove_and_replace_conventions() + { + var conventionSet = GetConventionSet(); + + Assert.DoesNotContain(conventionSet.ModelFinalizingConventions, c => c is TestConvention); + + conventionSet.Add(new TestConvention()); + + Assert.Contains(conventionSet.ModelFinalizingConventions, c => c is TestConvention); + Assert.DoesNotContain(conventionSet.ModelInitializedConventions, c => c is DerivedTestConvention); + + conventionSet.Replace(new DerivedTestConvention()); + + Assert.Contains(conventionSet.ModelFinalizingConventions, c => c is DerivedTestConvention); + Assert.Contains(conventionSet.ModelInitializedConventions, c => c is DerivedTestConvention); + + conventionSet.Remove(typeof(TestConvention)); + + Assert.DoesNotContain(conventionSet.ModelFinalizingConventions, c => c is TestConvention); + } + + protected class TestConvention : IModelFinalizingConvention + { + public void ProcessModelFinalizing( + IConventionModelBuilder modelBuilder, + IConventionContext context) + { + } + } + + protected class DerivedTestConvention : TestConvention, IModelInitializedConvention + { + public void ProcessModelInitialized( + IConventionModelBuilder modelBuilder, + IConventionContext context) + { + } + } + protected virtual ConventionSet GetConventionSet() => InMemoryConventionSetBuilder.Build();