diff --git a/src/EFCore.Relational/Diagnostics/IndexInvalidPropertiesEventData.cs b/src/EFCore.Relational/Diagnostics/IndexWithPropertiesEventData.cs similarity index 97% rename from src/EFCore.Relational/Diagnostics/IndexInvalidPropertiesEventData.cs rename to src/EFCore.Relational/Diagnostics/IndexWithPropertiesEventData.cs index f55a60f5fc9..686ce11ba98 100644 --- a/src/EFCore.Relational/Diagnostics/IndexInvalidPropertiesEventData.cs +++ b/src/EFCore.Relational/Diagnostics/IndexWithPropertiesEventData.cs @@ -13,7 +13,7 @@ namespace Microsoft.EntityFrameworkCore.Diagnostics /// A event payload class for the /// event. /// - public class IndexInvalidPropertiesEventData : EventData + public class IndexWithPropertiesEventData : EventData { /// /// Constructs the event payload for the event. @@ -27,7 +27,7 @@ public class IndexInvalidPropertiesEventData : EventData /// The tables mapped to the first property. /// The name of the second property name which causes this event. /// The tables mapped to the second property. - public IndexInvalidPropertiesEventData( + public IndexWithPropertiesEventData( [NotNull] EventDefinitionBase eventDefinition, [NotNull] Func messageGenerator, [NotNull] IEntityType entityType, diff --git a/src/EFCore.Relational/Diagnostics/IndexInvalidPropertyEventData.cs b/src/EFCore.Relational/Diagnostics/IndexWithPropertyEventData.cs similarity index 89% rename from src/EFCore.Relational/Diagnostics/IndexInvalidPropertyEventData.cs rename to src/EFCore.Relational/Diagnostics/IndexWithPropertyEventData.cs index cbaaf9d87b6..82c33c189e4 100644 --- a/src/EFCore.Relational/Diagnostics/IndexInvalidPropertyEventData.cs +++ b/src/EFCore.Relational/Diagnostics/IndexWithPropertyEventData.cs @@ -13,7 +13,7 @@ namespace Microsoft.EntityFrameworkCore.Diagnostics /// A event payload class for /// the events involving an invalid property name on an index. /// - public class IndexInvalidPropertyEventData : EventData + public class IndexWithPropertyEventData : EventData { /// /// Constructs the event payload for indexes with a invalid property. @@ -24,7 +24,7 @@ public class IndexInvalidPropertyEventData : EventData /// The name of the index. /// The names of the properties which define the index. /// The property name which is invalid. - public IndexInvalidPropertyEventData( + public IndexWithPropertyEventData( [NotNull] EventDefinitionBase eventDefinition, [NotNull] Func messageGenerator, [NotNull] IEntityType entityType, @@ -36,7 +36,7 @@ public IndexInvalidPropertyEventData( EntityType = entityType; Name = indexName; PropertyNames = indexPropertyNames; - InvalidPropertyName = invalidPropertyName; + PropertyName = invalidPropertyName; } /// @@ -55,8 +55,8 @@ public IndexInvalidPropertyEventData( public virtual List PropertyNames { get; } /// - /// The name of the invalid property. + /// The name of the specific property. /// - public virtual string InvalidPropertyName { get; } + public virtual string PropertyName { get; } } } diff --git a/src/EFCore.Relational/Diagnostics/RelationalEventId.cs b/src/EFCore.Relational/Diagnostics/RelationalEventId.cs index 8425d1c7c08..45f08af32ac 100644 --- a/src/EFCore.Relational/Diagnostics/RelationalEventId.cs +++ b/src/EFCore.Relational/Diagnostics/RelationalEventId.cs @@ -674,7 +674,7 @@ private enum Id /// This event is in the category. /// /// - /// This event uses the payload when used with a . + /// This event uses the payload when used with a . /// /// public static readonly EventId IndexPropertiesBothMappedAndNotMappedToTable = MakeValidationId(Id.IndexPropertiesBothMappedAndNotMappedToTable); @@ -687,7 +687,7 @@ private enum Id /// This event is in the category. /// /// - /// This event uses the payload when used with a . + /// This event uses the payload when used with a . /// /// public static readonly EventId IndexPropertiesMappedToNonOverlappingTables = MakeValidationId(Id.IndexPropertiesMappedToNonOverlappingTables); diff --git a/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs b/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs index 6bf3eb1fcbd..a12646bc319 100644 --- a/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs +++ b/src/EFCore.Relational/Diagnostics/RelationalLoggerExtensions.cs @@ -4460,7 +4460,7 @@ public static void IndexPropertiesBothMappedAndNotMappedToTable( if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled)) { - var eventData = new IndexInvalidPropertyEventData( + var eventData = new IndexWithPropertyEventData( definition, UnnamedIndexPropertiesBothMappedAndNotMappedToTable, entityType, @@ -4486,7 +4486,7 @@ public static void IndexPropertiesBothMappedAndNotMappedToTable( if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled)) { - var eventData = new IndexInvalidPropertyEventData( + var eventData = new IndexWithPropertyEventData( definition, NamedIndexPropertiesBothMappedAndNotMappedToTable, entityType, @@ -4502,22 +4502,22 @@ public static void IndexPropertiesBothMappedAndNotMappedToTable( private static string UnnamedIndexPropertiesBothMappedAndNotMappedToTable(EventDefinitionBase definition, EventData payload) { var d = (EventDefinition)definition; - var p = (IndexInvalidPropertyEventData)payload; + var p = (IndexWithPropertyEventData)payload; return d.GenerateMessage( p.EntityType.DisplayName(), p.PropertyNames.Format(), - p.InvalidPropertyName); + p.PropertyName); } private static string NamedIndexPropertiesBothMappedAndNotMappedToTable(EventDefinitionBase definition, EventData payload) { var d = (EventDefinition)definition; - var p = (IndexInvalidPropertyEventData)payload; + var p = (IndexWithPropertyEventData)payload; return d.GenerateMessage( p.Name, p.EntityType.DisplayName(), p.PropertyNames.Format(), - p.InvalidPropertyName); + p.PropertyName); } /// @@ -4556,7 +4556,7 @@ public static void IndexPropertiesMappedToNonOverlappingTables( if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled)) { - var eventData = new IndexInvalidPropertiesEventData( + var eventData = new IndexWithPropertiesEventData( definition, UnnamedIndexPropertiesMappedToNonOverlappingTables, entityType, @@ -4592,7 +4592,7 @@ public static void IndexPropertiesMappedToNonOverlappingTables( if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled)) { - var eventData = new IndexInvalidPropertiesEventData( + var eventData = new IndexWithPropertiesEventData( definition, NamedIndexPropertiesMappedToNonOverlappingTables, entityType, @@ -4611,7 +4611,7 @@ public static void IndexPropertiesMappedToNonOverlappingTables( private static string UnnamedIndexPropertiesMappedToNonOverlappingTables(EventDefinitionBase definition, EventData payload) { var d = (EventDefinition)definition; - var p = (IndexInvalidPropertiesEventData)payload; + var p = (IndexWithPropertiesEventData)payload; return d.GenerateMessage( p.EntityType.DisplayName(), p.PropertyNames.Format(), @@ -4624,7 +4624,7 @@ private static string UnnamedIndexPropertiesMappedToNonOverlappingTables(EventDe private static string NamedIndexPropertiesMappedToNonOverlappingTables(EventDefinitionBase definition, EventData payload) { var d = (FallbackEventDefinition)definition; - var p = (IndexInvalidPropertiesEventData)payload; + var p = (IndexWithPropertiesEventData)payload; return d.GenerateMessage( l => l.Log( d.Level, diff --git a/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs b/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs index 84138bfc529..ba82da0fa4e 100644 --- a/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs @@ -766,7 +766,7 @@ public static IEnumerable FindRowInternalForeignKeys( /// The entity type. /// The identifier of the store object. public static IEnumerable FindRowInternalForeignKeys( - [NotNull] this IMutableEntityType entityType, StoreObjectIdentifier storeObject) + [NotNull] this IMutableEntityType entityType, in StoreObjectIdentifier storeObject) => ((IEntityType)entityType).FindRowInternalForeignKeys(storeObject).Cast(); /// @@ -776,7 +776,7 @@ public static IEnumerable FindRowInternalForeignKeys( /// The entity type. /// The identifier of the store object. public static IEnumerable FindRowInternalForeignKeys( - [NotNull] this IConventionEntityType entityType, StoreObjectIdentifier storeObject) + [NotNull] this IConventionEntityType entityType, in StoreObjectIdentifier storeObject) => ((IEntityType)entityType).FindRowInternalForeignKeys(storeObject).Cast(); /// diff --git a/src/EFCore.Relational/Extensions/RelationalForeignKeyExtensions.cs b/src/EFCore.Relational/Extensions/RelationalForeignKeyExtensions.cs index 453bde9b57e..aa1f64fc255 100644 --- a/src/EFCore.Relational/Extensions/RelationalForeignKeyExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalForeignKeyExtensions.cs @@ -35,7 +35,7 @@ public static string GetConstraintName([NotNull] this IForeignKey foreignKey) /// The identifier of the principal store object. /// The foreign key constraint name. public static string GetConstraintName( - [NotNull] this IForeignKey foreignKey, StoreObjectIdentifier storeObject, StoreObjectIdentifier principalStoreObject) + [NotNull] this IForeignKey foreignKey, in StoreObjectIdentifier storeObject, in StoreObjectIdentifier principalStoreObject) { var annotation = foreignKey.FindAnnotation(RelationalAnnotationNames.Name); return annotation != null @@ -75,24 +75,32 @@ public static string GetDefaultName([NotNull] this IForeignKey foreignKey) /// The default constraint name that would be used for this foreign key. public static string GetDefaultName( [NotNull] this IForeignKey foreignKey, - StoreObjectIdentifier storeObject, - StoreObjectIdentifier principalStoreObject) + in StoreObjectIdentifier storeObject, + in StoreObjectIdentifier principalStoreObject) { - var propertyNames = foreignKey.Properties.Select(p => p.GetColumnName(storeObject)).ToList(); - var principalPropertyNames = foreignKey.PrincipalKey.Properties.Select(p => p.GetColumnName(storeObject)).ToList(); + var propertyNames = foreignKey.Properties.GetColumnNames(storeObject); + var principalPropertyNames = foreignKey.PrincipalKey.Properties.GetColumnNames(principalStoreObject); var rootForeignKey = foreignKey; // Limit traversal to avoid getting stuck in a cycle (validation will throw for these later) // Using a hashset is detrimental to the perf when there are no cycles for (var i = 0; i < Metadata.Internal.RelationalEntityTypeExtensions.MaxEntityTypesSharingTable; i++) { - var linkedForeignKey = rootForeignKey.DeclaringEntityType - .FindRowInternalForeignKeys(storeObject) - .SelectMany(fk => fk.PrincipalEntityType.GetForeignKeys()) - .FirstOrDefault(k => principalStoreObject.Name == k.PrincipalEntityType.GetTableName() - && principalStoreObject.Schema == k.PrincipalEntityType.GetSchema() - && propertyNames.SequenceEqual(k.Properties.Select(p => p.GetColumnName(storeObject))) - && principalPropertyNames.SequenceEqual(k.PrincipalKey.Properties.Select(p => p.GetColumnName(storeObject)))); + IForeignKey linkedForeignKey = null; + foreach (var otherForeignKey in rootForeignKey.DeclaringEntityType + .FindRowInternalForeignKeys(storeObject) + .SelectMany(fk => fk.PrincipalEntityType.GetForeignKeys())) + { + if (principalStoreObject.Name == otherForeignKey.PrincipalEntityType.GetTableName() + && principalStoreObject.Schema == otherForeignKey.PrincipalEntityType.GetSchema() + && propertyNames.SequenceEqual(otherForeignKey.Properties.GetColumnNames(storeObject)) + && principalPropertyNames.SequenceEqual(otherForeignKey.PrincipalKey.Properties.GetColumnNames(principalStoreObject))) + { + linkedForeignKey = otherForeignKey; + break; + } + } + if (linkedForeignKey == null) { break; @@ -112,7 +120,7 @@ public static string GetDefaultName( .Append("_") .Append(principalStoreObject.Name) .Append("_") - .AppendJoin(foreignKey.Properties.Select(p => p.GetColumnName(storeObject)), "_") + .AppendJoin(propertyNames, "_") .ToString(); return Uniquifier.Truncate(baseName, foreignKey.DeclaringEntityType.Model.GetMaxIdentifierLength()); @@ -176,7 +184,7 @@ public static IEnumerable GetMappedConstraints([NotNull] /// The foreign key. /// The identifier of the containing store object. /// The foreign key if found, or if none was found. - public static IForeignKey FindSharedObjectRootForeignKey([NotNull] this IForeignKey foreignKey, StoreObjectIdentifier storeObject) + public static IForeignKey FindSharedObjectRootForeignKey([NotNull] this IForeignKey foreignKey, in StoreObjectIdentifier storeObject) { Check.NotNull(foreignKey, nameof(foreignKey)); @@ -188,12 +196,22 @@ public static IForeignKey FindSharedObjectRootForeignKey([NotNull] this IForeign // Using a hashset is detrimental to the perf when there are no cycles for (var i = 0; i < Metadata.Internal.RelationalEntityTypeExtensions.MaxEntityTypesSharingTable; i++) { - var linkedKey = rootForeignKey.DeclaringEntityType + IForeignKey linkedKey = null; + foreach (var otherForeignKey in rootForeignKey.DeclaringEntityType .FindRowInternalForeignKeys(storeObject) - .SelectMany(fk => fk.PrincipalEntityType.GetForeignKeys()) - .FirstOrDefault(k => k.GetConstraintName(storeObject, - StoreObjectIdentifier.Table(k.PrincipalEntityType.GetTableName(), k.PrincipalEntityType.GetSchema())) - == foreignKeyName); + .SelectMany(fk => fk.PrincipalEntityType.GetForeignKeys())) + { + if (otherForeignKey.GetConstraintName(storeObject, + StoreObjectIdentifier.Table( + otherForeignKey.PrincipalEntityType.GetTableName(), + otherForeignKey.PrincipalEntityType.GetSchema())) + == foreignKeyName) + { + linkedKey = otherForeignKey; + break; + } + } + if (linkedKey == null) { break; @@ -218,7 +236,7 @@ public static IForeignKey FindSharedObjectRootForeignKey([NotNull] this IForeign /// The identifier of the containing store object. /// The foreign key if found, or if none was found. public static IMutableForeignKey FindSharedObjectRootForeignKey( - [NotNull] this IMutableForeignKey foreignKey, StoreObjectIdentifier storeObject) + [NotNull] this IMutableForeignKey foreignKey, in StoreObjectIdentifier storeObject) => (IMutableForeignKey)((IForeignKey)foreignKey).FindSharedObjectRootForeignKey(storeObject); /// @@ -234,7 +252,7 @@ public static IMutableForeignKey FindSharedObjectRootForeignKey( /// The identifier of the containing store object. /// The foreign key if found, or if none was found. public static IConventionForeignKey FindSharedObjectRootForeignKey( - [NotNull] this IConventionForeignKey foreignKey, StoreObjectIdentifier storeObject) + [NotNull] this IConventionForeignKey foreignKey, in StoreObjectIdentifier storeObject) => (IConventionForeignKey)((IForeignKey)foreignKey).FindSharedObjectRootForeignKey(storeObject); } } diff --git a/src/EFCore.Relational/Extensions/RelationalIndexExtensions.cs b/src/EFCore.Relational/Extensions/RelationalIndexExtensions.cs index 5b5c3ae3973..d1c11846955 100644 --- a/src/EFCore.Relational/Extensions/RelationalIndexExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalIndexExtensions.cs @@ -43,7 +43,7 @@ public static string GetName([NotNull] this IIndex index) /// The index. /// The identifier of the store object. /// The name of the index in the database. - public static string GetDatabaseName([NotNull] this IIndex index, StoreObjectIdentifier storeObject) + public static string GetDatabaseName([NotNull] this IIndex index, in StoreObjectIdentifier storeObject) => (string)index[RelationalAnnotationNames.Name] ?? index.Name ?? index.GetDefaultDatabaseName(storeObject); @@ -82,19 +82,27 @@ public static string GetDefaultName([NotNull] this IIndex index) /// The index. /// The identifier of the store object. /// The default name that would be used for this index. - public static string GetDefaultDatabaseName([NotNull] this IIndex index, StoreObjectIdentifier storeObject) + public static string GetDefaultDatabaseName([NotNull] this IIndex index, in StoreObjectIdentifier storeObject) { - var propertyNames = index.Properties.Select(p => p.GetColumnName(storeObject)).ToList(); + var propertyNames = index.Properties.GetColumnNames(storeObject); var rootIndex = index; // Limit traversal to avoid getting stuck in a cycle (validation will throw for these later) // Using a hashset is detrimental to the perf when there are no cycles for (var i = 0; i < Metadata.Internal.RelationalEntityTypeExtensions.MaxEntityTypesSharingTable; i++) { - var linkedIndex = rootIndex.DeclaringEntityType + IIndex linkedIndex = null; + foreach(var otherIndex in rootIndex.DeclaringEntityType .FindRowInternalForeignKeys(storeObject) - .SelectMany(fk => fk.PrincipalEntityType.GetIndexes()) - .FirstOrDefault(i => i.Properties.Select(p => p.GetColumnName(storeObject)).SequenceEqual(propertyNames)); + .SelectMany(fk => fk.PrincipalEntityType.GetIndexes())) + { + if (otherIndex.Properties.GetColumnNames(storeObject).SequenceEqual(propertyNames)) + { + linkedIndex = otherIndex; + break; + } + } + if (linkedIndex == null) { break; @@ -201,7 +209,7 @@ public static string GetFilter([NotNull] this IIndex index) /// The index. /// The identifier of the containing store object. /// The index filter expression. - public static string GetFilter([NotNull] this IIndex index, StoreObjectIdentifier storeObject) + public static string GetFilter([NotNull] this IIndex index, in StoreObjectIdentifier storeObject) { var annotation = index.FindAnnotation(RelationalAnnotationNames.Filter); if (annotation != null) @@ -269,7 +277,7 @@ public static IEnumerable GetMappedTableIndexes([NotNull] this IInd /// The index. /// The identifier of the containing store object. /// The index found, or if none was found. - public static IIndex FindSharedObjectRootIndex([NotNull] this IIndex index, StoreObjectIdentifier storeObject) + public static IIndex FindSharedObjectRootIndex([NotNull] this IIndex index, in StoreObjectIdentifier storeObject) { Check.NotNull(index, nameof(index)); @@ -280,10 +288,18 @@ public static IIndex FindSharedObjectRootIndex([NotNull] this IIndex index, Stor // Using a hashset is detrimental to the perf when there are no cycles for (var i = 0; i < Metadata.Internal.RelationalEntityTypeExtensions.MaxEntityTypesSharingTable; i++) { - var linkedIndex = rootIndex.DeclaringEntityType + IIndex linkedIndex = null; + foreach(var otherIndex in rootIndex.DeclaringEntityType .FindRowInternalForeignKeys(storeObject) - .SelectMany(fk => fk.PrincipalEntityType.GetIndexes()) - .FirstOrDefault(i => i.GetDatabaseName(storeObject) == indexName); + .SelectMany(fk => fk.PrincipalEntityType.GetIndexes())) + { + if (otherIndex.GetDatabaseName(storeObject) == indexName) + { + linkedIndex = otherIndex; + break; + } + } + if (linkedIndex == null) { break; @@ -308,7 +324,7 @@ public static IIndex FindSharedObjectRootIndex([NotNull] this IIndex index, Stor /// The identifier of the containing store object. /// The index found, or if none was found. public static IMutableIndex FindSharedObjectRootIndex( - [NotNull] this IMutableIndex index, StoreObjectIdentifier storeObject) + [NotNull] this IMutableIndex index, in StoreObjectIdentifier storeObject) => (IMutableIndex)((IIndex)index).FindSharedObjectRootIndex(storeObject); /// @@ -324,7 +340,7 @@ public static IMutableIndex FindSharedObjectRootIndex( /// The identifier of the containing store object. /// The index found, or if none was found. public static IConventionIndex FindSharedObjectRootIndex( - [NotNull] this IConventionIndex index, StoreObjectIdentifier storeObject) + [NotNull] this IConventionIndex index, in StoreObjectIdentifier storeObject) => (IConventionIndex)((IIndex)index).FindSharedObjectRootIndex(storeObject); } } diff --git a/src/EFCore.Relational/Extensions/RelationalKeyExtensions.cs b/src/EFCore.Relational/Extensions/RelationalKeyExtensions.cs index c7813ff408f..a51120de937 100644 --- a/src/EFCore.Relational/Extensions/RelationalKeyExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalKeyExtensions.cs @@ -31,7 +31,7 @@ public static string GetName([NotNull] this IKey key) /// The key. /// The identifier of the containing store object. /// The key constraint name for this key. - public static string GetName([NotNull] this IKey key, StoreObjectIdentifier storeObject) + public static string GetName([NotNull] this IKey key, in StoreObjectIdentifier storeObject) => (string)key[RelationalAnnotationNames.Name] ?? key.GetDefaultName(storeObject); @@ -67,7 +67,7 @@ public static string GetDefaultName([NotNull] this IKey key) /// The key. /// The identifier of the containing store object. /// The default key constraint name that would be used for this key. - public static string GetDefaultName([NotNull] this IKey key, StoreObjectIdentifier storeObject) + public static string GetDefaultName([NotNull] this IKey key, in StoreObjectIdentifier storeObject) { string name = null; if (key.IsPrimaryKey()) @@ -97,17 +97,25 @@ public static string GetDefaultName([NotNull] this IKey key, StoreObjectIdentifi } else { - var propertyNames = key.Properties.Select(p => p.GetColumnName(storeObject)).ToList(); + var propertyNames = key.Properties.GetColumnNames(storeObject); var rootKey = key; // Limit traversal to avoid getting stuck in a cycle (validation will throw for these later) // Using a hashset is detrimental to the perf when there are no cycles for (var i = 0; i < Metadata.Internal.RelationalEntityTypeExtensions.MaxEntityTypesSharingTable; i++) { - var linkedKey = rootKey.DeclaringEntityType + IKey linkedKey = null; + foreach(var otherKey in rootKey.DeclaringEntityType .FindRowInternalForeignKeys(storeObject) - .SelectMany(fk => fk.PrincipalEntityType.GetKeys()) - .FirstOrDefault(k => k.Properties.Select(p => p.GetColumnName(storeObject)).SequenceEqual(propertyNames)); + .SelectMany(fk => fk.PrincipalEntityType.GetKeys())) + { + if (otherKey.Properties.GetColumnNames(storeObject).SequenceEqual(propertyNames)) + { + linkedKey = otherKey; + break; + } + } + if (linkedKey == null) { break; @@ -125,7 +133,7 @@ public static string GetDefaultName([NotNull] this IKey key, StoreObjectIdentifi .Append("AK_") .Append(storeObject.Name) .Append("_") - .AppendJoin(key.Properties.Select(p => p.GetColumnName(storeObject)), "_") + .AppendJoin(propertyNames, "_") .ToString(); } @@ -188,7 +196,7 @@ public static IEnumerable GetMappedConstraints([NotNull] this /// The key. /// The identifier of the containing store object. /// The key found, or if none was found. - public static IKey FindSharedObjectRootKey([NotNull] this IKey key, StoreObjectIdentifier storeObject) + public static IKey FindSharedObjectRootKey([NotNull] this IKey key, in StoreObjectIdentifier storeObject) { Check.NotNull(key, nameof(key)); @@ -199,10 +207,18 @@ public static IKey FindSharedObjectRootKey([NotNull] this IKey key, StoreObjectI // Using a hashset is detrimental to the perf when there are no cycles for (var i = 0; i < Metadata.Internal.RelationalEntityTypeExtensions.MaxEntityTypesSharingTable; i++) { - var linkedKey = rootKey.DeclaringEntityType + IKey linkedKey = null; + foreach (var otherKey in rootKey.DeclaringEntityType .FindRowInternalForeignKeys(storeObject) - .SelectMany(fk => fk.PrincipalEntityType.GetKeys()) - .FirstOrDefault(k => k.GetName(storeObject) == keyName); + .SelectMany(fk => fk.PrincipalEntityType.GetKeys())) + { + if (otherKey.GetName(storeObject) == keyName) + { + linkedKey = otherKey; + break; + } + } + if (linkedKey == null) { break; @@ -227,7 +243,7 @@ public static IKey FindSharedObjectRootKey([NotNull] this IKey key, StoreObjectI /// The identifier of the containing store object. /// The key found, or if none was found. public static IMutableKey FindSharedObjectRootKey( - [NotNull] this IMutableKey key, StoreObjectIdentifier storeObject) + [NotNull] this IMutableKey key, in StoreObjectIdentifier storeObject) => (IMutableKey)((IKey)key).FindSharedObjectRootKey(storeObject); /// @@ -243,7 +259,7 @@ public static IMutableKey FindSharedObjectRootKey( /// The identifier of the containing store object. /// The key found, or if none was found. public static IConventionKey FindSharedObjectRootKey( - [NotNull] this IConventionKey key, StoreObjectIdentifier storeObject) + [NotNull] this IConventionKey key, in StoreObjectIdentifier storeObject) => (IConventionKey)((IKey)key).FindSharedObjectRootKey(storeObject); } } diff --git a/src/EFCore.Relational/Extensions/RelationalPropertyBuilderExtensions.cs b/src/EFCore.Relational/Extensions/RelationalPropertyBuilderExtensions.cs index 3f8358e7e17..894ebeed952 100644 --- a/src/EFCore.Relational/Extensions/RelationalPropertyBuilderExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalPropertyBuilderExtensions.cs @@ -84,7 +84,7 @@ public static IConventionPropertyBuilder HasColumnName( public static IConventionPropertyBuilder HasColumnName( [NotNull] this IConventionPropertyBuilder propertyBuilder, [CanBeNull] string name, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, bool fromDataAnnotation = false) { if (!propertyBuilder.CanSetColumnName(name, storeObject, fromDataAnnotation)) @@ -120,7 +120,7 @@ public static bool CanSetColumnName( public static bool CanSetColumnName( [NotNull] this IConventionPropertyBuilder propertyBuilder, [CanBeNull] string name, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, bool fromDataAnnotation = false) { var overrides = RelationalPropertyOverrides.Find(propertyBuilder.Metadata, storeObject); diff --git a/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs b/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs index 069fa6a2086..4b9ba74e622 100644 --- a/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs @@ -40,7 +40,7 @@ public static string GetColumnName([NotNull] this IProperty property) /// The property. /// The identifier of the table-like store object containing the column. /// The name of the column to which the property is mapped. - public static string GetColumnName([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static string GetColumnName([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { Check.NotNull(property, nameof(property)); @@ -73,7 +73,7 @@ public static string GetDefaultColumnName([NotNull] this IProperty property) /// The property. /// The identifier of the table-like store object containing the column. /// The default column name to which the property would be mapped. - public static string GetDefaultColumnName([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static string GetDefaultColumnName([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { var sharedTablePrincipalPrimaryKeyProperty = FindSharedObjectRootPrimaryKeyProperty(property, storeObject); if (sharedTablePrincipalPrimaryKeyProperty != null) @@ -188,7 +188,7 @@ public static string SetColumnName( /// The name to set. /// The identifier of the table-like store object containing the column. public static void SetColumnName( - [NotNull] this IMutableProperty property, [CanBeNull] string name, StoreObjectIdentifier storeObject) + [NotNull] this IMutableProperty property, [CanBeNull] string name, in StoreObjectIdentifier storeObject) => RelationalPropertyOverrides.GetOrCreate(property, storeObject) .SetColumnName(name, ConfigurationSource.Explicit); @@ -203,7 +203,7 @@ public static void SetColumnName( public static string SetColumnName( [NotNull] this IConventionProperty property, [CanBeNull] string name, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, bool fromDataAnnotation = false) => RelationalPropertyOverrides.GetOrCreate(property, storeObject) .SetColumnName(name, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention); @@ -224,7 +224,7 @@ public static string SetColumnName( /// The for the column name for a particular table-like store object. public static ConfigurationSource? GetColumnNameConfigurationSource( [NotNull] this IConventionProperty property, - StoreObjectIdentifier storeObject) + in StoreObjectIdentifier storeObject) => RelationalPropertyOverrides.Find(property, storeObject)?.GetColumnNameConfigurationSource(); /// @@ -246,7 +246,7 @@ public static string GetColumnType([NotNull] this IProperty property) /// The property. /// The identifier of the table-like store object containing the column. /// The database type of the column to which the property is mapped. - public static string GetColumnType([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static string GetColumnType([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { var annotation = property.FindAnnotation(RelationalAnnotationNames.ColumnType); if (annotation != null) @@ -257,7 +257,7 @@ public static string GetColumnType([NotNull] this IProperty property, StoreObjec return GetDefaultColumnType(property, storeObject); } - private static string GetDefaultColumnType(IProperty property, StoreObjectIdentifier storeObject) + private static string GetDefaultColumnType(IProperty property, in StoreObjectIdentifier storeObject) { var sharedTableRootProperty = property.FindSharedStoreObjectRootProperty(storeObject); return sharedTableRootProperty != null @@ -352,26 +352,50 @@ public static IEnumerable GetFunctionColumnMappings([Not /// The property. /// The identifier of the table-like store object containing the column. /// The column to which the property is mapped. - public static IColumnBase FindColumn([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static IColumnBase FindColumn([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { switch (storeObject.StoreObjectType) { case StoreObjectType.Table: - return property.GetTableColumnMappings() - .Where(m => m.TableMapping.Table.Name == storeObject.Name && m.TableMapping.Table.Schema == storeObject.Schema) - .FirstOrDefault()?.Column; + foreach (var mapping in property.GetTableColumnMappings()) + { + if (mapping.TableMapping.Table.Name == storeObject.Name && mapping.TableMapping.Table.Schema == storeObject.Schema) + { + return mapping.Column; + } + } + + return null; case StoreObjectType.View: - return property.GetViewColumnMappings() - .Where(m => m.ViewMapping.Table.Name == storeObject.Name && m.ViewMapping.Table.Schema == storeObject.Schema) - .FirstOrDefault()?.Column; + foreach (var mapping in property.GetViewColumnMappings()) + { + if (mapping.TableMapping.Table.Name == storeObject.Name && mapping.TableMapping.Table.Schema == storeObject.Schema) + { + return mapping.Column; + } + } + + return null; case StoreObjectType.SqlQuery: - return property.GetSqlQueryColumnMappings() - .Where(m => m.SqlQueryMapping.SqlQuery.Name == storeObject.Name) - .FirstOrDefault()?.Column; + foreach (var mapping in property.GetSqlQueryColumnMappings()) + { + if (mapping.TableMapping.Table.Name == storeObject.Name) + { + return mapping.Column; + } + } + + return null; case StoreObjectType.Function: - return property.GetFunctionColumnMappings() - .Where(m => m.FunctionMapping.DbFunction.Name == storeObject.Name) - .FirstOrDefault()?.Column; + foreach (var mapping in property.GetFunctionColumnMappings()) + { + if (mapping.TableMapping.Table.Name == storeObject.Name) + { + return mapping.Column; + } + } + + return null; default: throw new NotImplementedException(storeObject.StoreObjectType.ToString()); } @@ -394,7 +418,7 @@ public static string GetDefaultValueSql([NotNull] this IProperty property) /// The property. /// The identifier of the table-like store object containing the column. /// The SQL expression that is used as the default value for the column this property is mapped to. - public static string GetDefaultValueSql([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static string GetDefaultValueSql([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { var annotation = property.FindAnnotation(RelationalAnnotationNames.DefaultValueSql); if (annotation != null) @@ -469,7 +493,7 @@ public static string GetComputedColumnSql([NotNull] this IProperty property) /// The property. /// The identifier of the table-like store object containing the column. /// The SQL expression that is used as the computed value for the column this property is mapped to. - public static string GetComputedColumnSql([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static string GetComputedColumnSql([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { var annotation = property.FindAnnotation(RelationalAnnotationNames.ComputedColumnSql); if (annotation != null) @@ -547,7 +571,7 @@ public static string SetComputedColumnSql( /// Whether the value of the computed column this property is mapped to is stored in the database, /// or calculated when it is read. /// - public static bool? GetIsStored([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static bool? GetIsStored([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { var annotation = property.FindAnnotation(RelationalAnnotationNames.IsStored); if (annotation != null) @@ -616,7 +640,7 @@ public static object GetDefaultValue([NotNull] this IProperty property) /// The property. /// The identifier of the table-like store object containing the column. /// The object that is used as the default value for the column this property is mapped to. - public static object GetDefaultValue([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static object GetDefaultValue([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { var annotation = property.FindAnnotation(RelationalAnnotationNames.DefaultValue); if (annotation != null) @@ -708,7 +732,7 @@ private static object ConvertDefaultValue([NotNull] IProperty property, [CanBeNu /// The property. /// The identifier of the table-like store object containing the column. /// A flag indicating if the property as capable of storing only fixed-length data, such as strings. - public static bool? IsFixedLength([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static bool? IsFixedLength([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { var annotation = property.FindAnnotation(RelationalAnnotationNames.IsFixedLength); if (annotation != null) @@ -786,7 +810,7 @@ public static bool IsColumnNullable([NotNull] this IProperty property) /// The . /// The identifier of the table-like store object containing the column. /// if the mapped column is nullable; otherwise. - public static bool IsColumnNullable([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static bool IsColumnNullable([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { if (property.IsPrimaryKey()) { @@ -821,7 +845,7 @@ public static string GetComment([NotNull] this IProperty property) /// The property. /// The identifier of the table-like store object containing the column. /// The comment for the column this property is mapped to. - public static string GetComment([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static string GetComment([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { var annotation = property.FindAnnotation(RelationalAnnotationNames.Comment); if (annotation != null) @@ -887,7 +911,7 @@ public static string GetCollation([NotNull] this IProperty property) /// The property. /// The identifier of the table-like store object containing the column. /// The collation for the column this property is mapped to. - public static string GetCollation([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static string GetCollation([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { var annotation = property.FindAnnotation(RelationalAnnotationNames.Collation); if (annotation != null) @@ -971,7 +995,7 @@ public static RelationalTypeMapping FindRelationalTypeMapping([NotNull] this IPr /// The identifier of the table-like store object containing the column. /// The type mapping, or if none was found. public static RelationalTypeMapping FindRelationalTypeMapping( - [NotNull] this IProperty property, StoreObjectIdentifier storeObject) + [NotNull] this IProperty property, in StoreObjectIdentifier storeObject) => property.FindRelationalTypeMapping(); /// @@ -987,7 +1011,7 @@ public static RelationalTypeMapping FindRelationalTypeMapping( /// The identifier of the table-like store object containing the column. /// The property found, or if none was found. public static IProperty FindSharedStoreObjectRootProperty( - [NotNull] this IProperty property, StoreObjectIdentifier storeObject) + [NotNull] this IProperty property, in StoreObjectIdentifier storeObject) => FindSharedObjectRootProperty(property, storeObject); /// @@ -1003,7 +1027,7 @@ public static IProperty FindSharedStoreObjectRootProperty( /// The identifier of the table-like store object containing the column. /// The property found, or if none was found. public static IMutableProperty FindSharedStoreObjectRootProperty( - [NotNull] this IMutableProperty property, StoreObjectIdentifier storeObject) + [NotNull] this IMutableProperty property, in StoreObjectIdentifier storeObject) => (IMutableProperty)FindSharedObjectRootProperty(property, storeObject); /// @@ -1019,10 +1043,10 @@ public static IMutableProperty FindSharedStoreObjectRootProperty( /// The identifier of the table-like store object containing the column. /// The property found, or if none was found. public static IConventionProperty FindSharedStoreObjectRootProperty( - [NotNull] this IConventionProperty property, StoreObjectIdentifier storeObject) + [NotNull] this IConventionProperty property, in StoreObjectIdentifier storeObject) => (IConventionProperty)FindSharedObjectRootProperty(property, storeObject); - private static IProperty FindSharedObjectRootProperty([NotNull] IProperty property, StoreObjectIdentifier storeObject) + private static IProperty FindSharedObjectRootProperty([NotNull] IProperty property, in StoreObjectIdentifier storeObject) { Check.NotNull(property, nameof(property)); @@ -1040,10 +1064,18 @@ private static IProperty FindSharedObjectRootProperty([NotNull] IProperty proper // Using a hashset is detrimental to the perf when there are no cycles for (var i = 0; i < Metadata.Internal.RelationalEntityTypeExtensions.MaxEntityTypesSharingTable; i++) { - var linkedProperty = rootProperty.DeclaringEntityType + IProperty linkedProperty = null; + foreach (var p in rootProperty.DeclaringEntityType .FindRowInternalForeignKeys(storeObject) - .SelectMany(fk => fk.PrincipalEntityType.GetProperties()) - .FirstOrDefault(p => p.GetColumnName(storeObject) == column); + .SelectMany(fk => fk.PrincipalEntityType.GetProperties())) + { + if (p.GetColumnName(storeObject) == column) + { + linkedProperty = p; + break; + } + } + if (linkedProperty == null) { break; @@ -1055,7 +1087,7 @@ private static IProperty FindSharedObjectRootProperty([NotNull] IProperty proper return rootProperty == property ? null : rootProperty; } - private static IProperty FindSharedObjectRootPrimaryKeyProperty([NotNull] IProperty property, StoreObjectIdentifier storeObject) + private static IProperty FindSharedObjectRootPrimaryKeyProperty([NotNull] IProperty property, in StoreObjectIdentifier storeObject) { if (!property.IsPrimaryKey()) { @@ -1081,7 +1113,7 @@ private static IProperty FindSharedObjectRootPrimaryKeyProperty([NotNull] IPrope return principalProperty == property ? null : principalProperty; } - private static IProperty FindSharedObjectRootConcurrencyTokenProperty([NotNull] IProperty property, StoreObjectIdentifier storeObject) + private static IProperty FindSharedObjectRootConcurrencyTokenProperty([NotNull] IProperty property, in StoreObjectIdentifier storeObject) { if (!property.IsConcurrencyToken) { @@ -1123,7 +1155,7 @@ private static IProperty FindSharedObjectRootConcurrencyTokenProperty([NotNull] /// The property. /// The identifier of the table-like store object containing the column. /// An object that stores property facet overrides. - public static IAnnotatable FindOverrides([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static IAnnotatable FindOverrides([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) => RelationalPropertyOverrides.Find(property, storeObject); /// @@ -1139,7 +1171,7 @@ public static IAnnotatable FindOverrides([NotNull] this IProperty property, Stor /// The identifier of the table-like store object containing the column. /// An object that stores property facet overrides. public static IMutableAnnotatable GetOrCreateOverrides( - [NotNull] this IMutableProperty property, StoreObjectIdentifier storeObject) + [NotNull] this IMutableProperty property, in StoreObjectIdentifier storeObject) => RelationalPropertyOverrides.GetOrCreate(property, storeObject); /// @@ -1155,7 +1187,7 @@ public static IMutableAnnotatable GetOrCreateOverrides( /// The identifier of the table-like store object containing the column. /// An object that stores property facet overrides. public static IConventionAnnotatable GetOrCreateOverrides( - [NotNull] this IConventionProperty property, StoreObjectIdentifier storeObject) + [NotNull] this IConventionProperty property, in StoreObjectIdentifier storeObject) => RelationalPropertyOverrides.GetOrCreate(property, storeObject); } } diff --git a/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs b/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs index 83d9bc6027a..39167d2a7ef 100644 --- a/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs +++ b/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs @@ -600,7 +600,7 @@ private static bool IsIdentifyingPrincipal(IEntityType dependentEntityType, IEnt /// The logger to use. protected virtual void ValidateSharedColumnsCompatibility( [NotNull] IReadOnlyList mappedTypes, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, [NotNull] IDiagnosticsLogger logger) { var concurrencyColumns = TableSharingConcurrencyTokenConvention.GetConcurrencyTokensMap(storeObject, mappedTypes); @@ -643,8 +643,17 @@ protected virtual void ValidateSharedColumnsCompatibility( { foreach (var missingColumn in missingConcurrencyTokens) { - if (entityType.GetAllBaseTypesAscending().SelectMany(t => t.GetDeclaredProperties()) - .All(p => p.GetColumnName(storeObject) != missingColumn)) + var columnFound = false; + foreach (var property in entityType.GetAllBaseTypesAscending().SelectMany(t => t.GetDeclaredProperties())) + { + if (property.GetColumnName(storeObject) == missingColumn) + { + columnFound = true; + break; + } + } + + if (!columnFound) { throw new InvalidOperationException( RelationalStrings.MissingConcurrencyColumn(entityType.DisplayName(), missingColumn, storeObject.DisplayName())); @@ -666,7 +675,7 @@ protected virtual void ValidateCompatible( [NotNull] IProperty property, [NotNull] IProperty duplicateProperty, [NotNull] string columnName, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, [NotNull] IDiagnosticsLogger logger) { if (property.IsNullable != duplicateProperty.IsNullable) @@ -862,7 +871,7 @@ protected virtual void ValidateCompatible( /// The object that is used as the default value for the column the property is mapped to. protected virtual object GetDefaultColumnValue( [NotNull] IProperty property, - StoreObjectIdentifier storeObject) + in StoreObjectIdentifier storeObject) { var value = property.GetDefaultValue(storeObject); var converter = property.GetValueConverter() ?? property.FindRelationalTypeMapping(storeObject)?.Converter; @@ -880,7 +889,7 @@ protected virtual object GetDefaultColumnValue( /// The logger to use. protected virtual void ValidateSharedForeignKeysCompatibility( [NotNull] IReadOnlyList mappedTypes, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, [NotNull] IDiagnosticsLogger logger) { if (storeObject.StoreObjectType != StoreObjectType.Table) @@ -925,7 +934,7 @@ protected virtual void ValidateCompatible( [NotNull] IForeignKey foreignKey, [NotNull] IForeignKey duplicateForeignKey, [NotNull] string foreignKeyName, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, [NotNull] IDiagnosticsLogger logger) => foreignKey.AreCompatible(duplicateForeignKey, storeObject, shouldThrow: true); @@ -937,7 +946,7 @@ protected virtual void ValidateCompatible( /// The logger to use. protected virtual void ValidateSharedIndexesCompatibility( [NotNull] IReadOnlyList mappedTypes, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, [NotNull] IDiagnosticsLogger logger) { var indexMappings = new Dictionary(); @@ -966,7 +975,7 @@ protected virtual void ValidateCompatible( [NotNull] IIndex index, [NotNull] IIndex duplicateIndex, [NotNull] string indexName, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, [NotNull] IDiagnosticsLogger logger) => index.AreCompatible(duplicateIndex, storeObject, shouldThrow: true); @@ -978,7 +987,7 @@ protected virtual void ValidateCompatible( /// The logger to use. protected virtual void ValidateSharedKeysCompatibility( [NotNull] IReadOnlyList mappedTypes, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, [NotNull] IDiagnosticsLogger logger) { var keyMappings = new Dictionary(); @@ -1008,7 +1017,7 @@ protected virtual void ValidateCompatible( [NotNull] IKey key, [NotNull] IKey duplicateKey, [NotNull] string keyName, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, [NotNull] IDiagnosticsLogger logger) { key.AreCompatible(duplicateKey, storeObject, shouldThrow: true); diff --git a/src/EFCore.Relational/Infrastructure/RelationalPropertyExtensions.cs b/src/EFCore.Relational/Infrastructure/RelationalPropertyExtensions.cs index c84edf5cc48..8ae4336b394 100644 --- a/src/EFCore.Relational/Infrastructure/RelationalPropertyExtensions.cs +++ b/src/EFCore.Relational/Infrastructure/RelationalPropertyExtensions.cs @@ -23,5 +23,23 @@ public static string FormatColumns( [NotNull] this IEnumerable properties, StoreObjectIdentifier storeObject) => "{" + string.Join(", ", properties.Select(p => "'" + p.GetColumnName(storeObject) + "'")) + "}"; + + /// + /// Creates a list of column names. + /// + /// The properties to format. + /// The identifier of the table-like store object containing the column. + /// A list of column names. + public static IReadOnlyList GetColumnNames( + [NotNull] this IEnumerable properties, + in StoreObjectIdentifier storeObject) + { + var propertyNames = new List(); + foreach (var property in properties) + { + propertyNames.Add(property.GetColumnName(storeObject)); + } + return propertyNames; + } } } diff --git a/src/EFCore.Relational/Metadata/Conventions/RelationalValueGenerationConvention.cs b/src/EFCore.Relational/Metadata/Conventions/RelationalValueGenerationConvention.cs index 13116d8b086..c41ea62a1a1 100644 --- a/src/EFCore.Relational/Metadata/Conventions/RelationalValueGenerationConvention.cs +++ b/src/EFCore.Relational/Metadata/Conventions/RelationalValueGenerationConvention.cs @@ -145,7 +145,7 @@ private void ProcessTableChanged(IConventionEntityTypeBuilder entityTypeBuilder, /// The property. /// The identifier of the store object. /// The new store value generation strategy to set for the given property. - public static ValueGenerated? GetValueGenerated([NotNull] IProperty property, StoreObjectIdentifier storeObject) + public static ValueGenerated? GetValueGenerated([NotNull] IProperty property, in StoreObjectIdentifier storeObject) { var valueGenerated = GetValueGenerated(property); return valueGenerated ?? (property.GetComputedColumnSql(storeObject) != null diff --git a/src/EFCore.Relational/Metadata/Conventions/SharedTableConvention.cs b/src/EFCore.Relational/Metadata/Conventions/SharedTableConvention.cs index 13bad0c05d9..d375a36bd52 100644 --- a/src/EFCore.Relational/Metadata/Conventions/SharedTableConvention.cs +++ b/src/EFCore.Relational/Metadata/Conventions/SharedTableConvention.cs @@ -152,7 +152,7 @@ private static void TryUniquifyTableNames( private static void TryUniquifyColumnNames( IConventionEntityType entityType, Dictionary properties, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, int maxLength) { foreach (var property in entityType.GetDeclaredProperties()) @@ -234,7 +234,7 @@ private static string TryUniquify( private void TryUniquifyKeyNames( IConventionEntityType entityType, Dictionary keys, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, int maxLength) { foreach (var key in entityType.GetDeclaredKeys()) @@ -279,7 +279,7 @@ private void TryUniquifyKeyNames( protected virtual bool AreCompatible( [NotNull] IKey key, [NotNull] IKey duplicateKey, - StoreObjectIdentifier storeObject) + in StoreObjectIdentifier storeObject) => key.AreCompatible(duplicateKey, storeObject, shouldThrow: false); private static string TryUniquify( @@ -298,7 +298,7 @@ private static string TryUniquify( private void TryUniquifyIndexNames( IConventionEntityType entityType, Dictionary indexes, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, int maxLength) { foreach (var index in entityType.GetDeclaredIndexes()) @@ -341,7 +341,7 @@ private void TryUniquifyIndexNames( protected virtual bool AreCompatible( [NotNull] IIndex index, [NotNull] IIndex duplicateIndex, - StoreObjectIdentifier storeObject) + in StoreObjectIdentifier storeObject) => index.AreCompatible(duplicateIndex, storeObject, shouldThrow: false); private static string TryUniquify( @@ -360,7 +360,7 @@ private static string TryUniquify( private void TryUniquifyForeignKeyNames( IConventionEntityType entityType, Dictionary foreignKeys, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, int maxLength) { foreach (var foreignKey in entityType.GetDeclaredForeignKeys()) @@ -413,7 +413,7 @@ private void TryUniquifyForeignKeyNames( protected virtual bool AreCompatible( [NotNull] IForeignKey foreignKey, [NotNull] IForeignKey duplicateForeignKey, - StoreObjectIdentifier storeObject) + in StoreObjectIdentifier storeObject) => foreignKey.AreCompatible(duplicateForeignKey, storeObject, shouldThrow: false); private static string TryUniquify( diff --git a/src/EFCore.Relational/Metadata/Conventions/StoreGenerationConvention.cs b/src/EFCore.Relational/Metadata/Conventions/StoreGenerationConvention.cs index 0dc9d276c97..23f11803720 100644 --- a/src/EFCore.Relational/Metadata/Conventions/StoreGenerationConvention.cs +++ b/src/EFCore.Relational/Metadata/Conventions/StoreGenerationConvention.cs @@ -112,7 +112,7 @@ public virtual void ProcessModelFinalizing(IConventionModelBuilder modelBuilder, /// The identifier of the store object. protected virtual void Validate( [NotNull] IConventionProperty property, - StoreObjectIdentifier storeObject) + in StoreObjectIdentifier storeObject) { if (property.GetDefaultValue(storeObject) != null) { diff --git a/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs b/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs index 2d196ac25b0..b584c1ef101 100644 --- a/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs +++ b/src/EFCore.Relational/Metadata/Conventions/TableSharingConcurrencyTokenConvention.cs @@ -131,7 +131,7 @@ public virtual void ProcessModelFinalizing( /// [EntityFrameworkInternal] public static Dictionary> GetConcurrencyTokensMap( - StoreObjectIdentifier table, [NotNull] IReadOnlyList mappedTypes) + in StoreObjectIdentifier storeObject, [NotNull] IReadOnlyList mappedTypes) { if (mappedTypes.Count < 2) { @@ -156,7 +156,7 @@ public static Dictionary> GetConcurrencyTokensMap( continue; } - var columnName = property.GetColumnName(table); + var columnName = property.GetColumnName(storeObject); if (columnName == null) { continue; diff --git a/src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs b/src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs index 2931f39b4f3..719044bcd56 100644 --- a/src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs +++ b/src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Diagnostics; @@ -26,7 +27,7 @@ public static class RelationalForeignKeyExtensions public static bool AreCompatible( [NotNull] this IForeignKey foreignKey, [NotNull] IForeignKey duplicateForeignKey, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, bool shouldThrow) { var principalType = foreignKey.PrincipalEntityType; @@ -53,8 +54,7 @@ public static bool AreCompatible( return false; } - if (!foreignKey.Properties.Select(p => p.GetColumnName(storeObject)) - .SequenceEqual(duplicateForeignKey.Properties.Select(p => p.GetColumnName(storeObject)))) + if (!SameColumnNames(foreignKey.Properties, duplicateForeignKey.Properties, storeObject)) { if (shouldThrow) { @@ -75,8 +75,7 @@ public static bool AreCompatible( return false; } - if (!foreignKey.PrincipalKey.Properties.Select(p => p.GetColumnName(storeObject)) - .SequenceEqual(duplicateForeignKey.PrincipalKey.Properties.Select(p => p.GetColumnName(storeObject)))) + if (!SameColumnNames(foreignKey.PrincipalKey.Properties, duplicateForeignKey.PrincipalKey.Properties, storeObject)) { if (shouldThrow) { @@ -138,6 +137,12 @@ public static bool AreCompatible( } return true; + + static bool SameColumnNames( + IReadOnlyList properties, + IReadOnlyList duplicateProperties, + in StoreObjectIdentifier storeObject) + => properties.GetColumnNames(storeObject).SequenceEqual(duplicateProperties.GetColumnNames(storeObject)); } } } diff --git a/src/EFCore.Relational/Metadata/Internal/RelationalIndexExtensions.cs b/src/EFCore.Relational/Metadata/Internal/RelationalIndexExtensions.cs index 66a2c9343f1..7b66c4f5a41 100644 --- a/src/EFCore.Relational/Metadata/Internal/RelationalIndexExtensions.cs +++ b/src/EFCore.Relational/Metadata/Internal/RelationalIndexExtensions.cs @@ -26,11 +26,11 @@ public static class RelationalIndexExtensions public static bool AreCompatible( [NotNull] this IIndex index, [NotNull] IIndex duplicateIndex, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, bool shouldThrow) { - if (!index.Properties.Select(p => p.GetColumnName(storeObject)) - .SequenceEqual(duplicateIndex.Properties.Select(p => p.GetColumnName(storeObject)))) + if (!index.Properties.GetColumnNames(storeObject) + .SequenceEqual(duplicateIndex.Properties.GetColumnNames(storeObject))) { if (shouldThrow) { diff --git a/src/EFCore.Relational/Metadata/Internal/RelationalKeyExtensions.cs b/src/EFCore.Relational/Metadata/Internal/RelationalKeyExtensions.cs index 46b66f5dd2b..9f88ed257ea 100644 --- a/src/EFCore.Relational/Metadata/Internal/RelationalKeyExtensions.cs +++ b/src/EFCore.Relational/Metadata/Internal/RelationalKeyExtensions.cs @@ -26,11 +26,11 @@ public static class RelationalKeyExtensions public static bool AreCompatible( [NotNull] this IKey key, [NotNull] IKey duplicateKey, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, bool shouldThrow) { - if (!key.Properties.Select(p => p.GetColumnName(storeObject)) - .SequenceEqual(duplicateKey.Properties.Select(p => p.GetColumnName(storeObject)))) + if (!key.Properties.GetColumnNames(storeObject) + .SequenceEqual(duplicateKey.Properties.GetColumnNames(storeObject))) { if (shouldThrow) { diff --git a/src/EFCore.Relational/Metadata/Internal/RelationalPropertyOverrides.cs b/src/EFCore.Relational/Metadata/Internal/RelationalPropertyOverrides.cs index 1c8c6a606a7..31b19c813bc 100644 --- a/src/EFCore.Relational/Metadata/Internal/RelationalPropertyOverrides.cs +++ b/src/EFCore.Relational/Metadata/Internal/RelationalPropertyOverrides.cs @@ -60,7 +60,7 @@ public virtual string SetColumnName([CanBeNull] string columnName, Configuration /// 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 static RelationalPropertyOverrides Find([NotNull] IProperty property, StoreObjectIdentifier storeObject) + public static RelationalPropertyOverrides Find([NotNull] IProperty property, in StoreObjectIdentifier storeObject) { var tableOverrides = (SortedDictionary) property[RelationalAnnotationNames.RelationalOverrides]; @@ -77,7 +77,7 @@ public static RelationalPropertyOverrides Find([NotNull] IProperty property, Sto /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public static RelationalPropertyOverrides GetOrCreate( - [NotNull] IMutableProperty property, StoreObjectIdentifier storeObject) + [NotNull] IMutableProperty property, in StoreObjectIdentifier storeObject) { var tableOverrides = (SortedDictionary) property[RelationalAnnotationNames.RelationalOverrides]; @@ -103,7 +103,7 @@ public static RelationalPropertyOverrides GetOrCreate( /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public static RelationalPropertyOverrides GetOrCreate( - [NotNull] IConventionProperty property, StoreObjectIdentifier storeObject) + [NotNull] IConventionProperty property, in StoreObjectIdentifier storeObject) => GetOrCreate((IMutableProperty)property, storeObject); } } diff --git a/src/EFCore.Relational/Metadata/StoreObjectIdentifier.cs b/src/EFCore.Relational/Metadata/StoreObjectIdentifier.cs index 734ea2cde0f..e3303a2369c 100644 --- a/src/EFCore.Relational/Metadata/StoreObjectIdentifier.cs +++ b/src/EFCore.Relational/Metadata/StoreObjectIdentifier.cs @@ -10,8 +10,15 @@ namespace Microsoft.EntityFrameworkCore.Metadata /// /// A type that represents the id of a store object /// - public struct StoreObjectIdentifier : IComparable + public readonly struct StoreObjectIdentifier : IComparable { + private StoreObjectIdentifier(StoreObjectType storeObjectType, string name, string schema = null) + { + StoreObjectType = storeObjectType; + Name = name; + Schema = schema; + } + /// /// Creates a table id. /// @@ -22,7 +29,7 @@ public static StoreObjectIdentifier Table([NotNull] string name, [CanBeNull] str { Check.NotNull(name, nameof(name)); - return new StoreObjectIdentifier { StoreObjectType = StoreObjectType.Table, Name = name, Schema = schema }; + return new StoreObjectIdentifier(StoreObjectType.Table, name, schema); } /// @@ -35,7 +42,7 @@ public static StoreObjectIdentifier View([NotNull] string name, [CanBeNull] stri { Check.NotNull(name, nameof(name)); - return new StoreObjectIdentifier { StoreObjectType = StoreObjectType.View, Name = name, Schema = schema }; + return new StoreObjectIdentifier(StoreObjectType.View, name, schema); } /// @@ -47,7 +54,7 @@ public static StoreObjectIdentifier SqlQuery([NotNull] IEntityType entityType) { Check.NotNull(entityType, nameof(entityType)); - return new StoreObjectIdentifier { StoreObjectType = StoreObjectType.SqlQuery, Name = entityType.GetDefaultSqlQueryName() }; + return new StoreObjectIdentifier(StoreObjectType.SqlQuery, entityType.GetDefaultSqlQueryName()); } /// @@ -59,7 +66,7 @@ public static StoreObjectIdentifier SqlQuery([NotNull] string name) { Check.NotNull(name, nameof(name)); - return new StoreObjectIdentifier { StoreObjectType = StoreObjectType.SqlQuery, Name = name }; + return new StoreObjectIdentifier(StoreObjectType.SqlQuery, name); } /// @@ -71,23 +78,23 @@ public static StoreObjectIdentifier DbFunction([NotNull] string modelName) { Check.NotNull(modelName, nameof(modelName)); - return new StoreObjectIdentifier { StoreObjectType = StoreObjectType.Function, Name = modelName }; + return new StoreObjectIdentifier(StoreObjectType.Function, modelName); } /// /// Gets the table-like store object type. /// - public StoreObjectType StoreObjectType { get; private set; } + public StoreObjectType StoreObjectType { get; } /// /// Gets the table-like store object name. /// - public string Name { get; private set; } + public string Name { get; } /// /// Gets the table-like store object schema. /// - public string Schema { get; private set; } + public string Schema { get; } /// public int CompareTo(StoreObjectIdentifier other) diff --git a/src/EFCore.SqlServer/Extensions/SqlServerIndexExtensions.cs b/src/EFCore.SqlServer/Extensions/SqlServerIndexExtensions.cs index ef4b3b6f21e..7935e52ba54 100644 --- a/src/EFCore.SqlServer/Extensions/SqlServerIndexExtensions.cs +++ b/src/EFCore.SqlServer/Extensions/SqlServerIndexExtensions.cs @@ -29,7 +29,7 @@ public static class SqlServerIndexExtensions /// The index. /// The identifier of the store object. /// if the index is clustered. - public static bool? IsClustered([NotNull] this IIndex index, StoreObjectIdentifier storeObject) + public static bool? IsClustered([NotNull] this IIndex index, in StoreObjectIdentifier storeObject) { var annotation = index.FindAnnotation(SqlServerAnnotationNames.Clustered); if (annotation != null) @@ -40,7 +40,7 @@ public static class SqlServerIndexExtensions return GetDefaultIsClustered(index, storeObject); } - private static bool? GetDefaultIsClustered([NotNull] IIndex index, StoreObjectIdentifier storeObject) + private static bool? GetDefaultIsClustered([NotNull] IIndex index, in StoreObjectIdentifier storeObject) { var sharedTableRootIndex = index.FindSharedObjectRootIndex(storeObject); return sharedTableRootIndex?.IsClustered(storeObject); diff --git a/src/EFCore.SqlServer/Extensions/SqlServerKeyExtensions.cs b/src/EFCore.SqlServer/Extensions/SqlServerKeyExtensions.cs index 9103d379d16..c1faac01b87 100644 --- a/src/EFCore.SqlServer/Extensions/SqlServerKeyExtensions.cs +++ b/src/EFCore.SqlServer/Extensions/SqlServerKeyExtensions.cs @@ -27,7 +27,7 @@ public static class SqlServerKeyExtensions /// The key. /// The identifier of the store object. /// if the key is clustered. - public static bool? IsClustered([NotNull] this IKey key, StoreObjectIdentifier storeObject) + public static bool? IsClustered([NotNull] this IKey key, in StoreObjectIdentifier storeObject) { var annotation = key.FindAnnotation(SqlServerAnnotationNames.Clustered); if (annotation != null) @@ -38,7 +38,7 @@ public static class SqlServerKeyExtensions return GetDefaultIsClustered(key, storeObject); } - private static bool? GetDefaultIsClustered([NotNull] IKey key, StoreObjectIdentifier storeObject) + private static bool? GetDefaultIsClustered([NotNull] IKey key, in StoreObjectIdentifier storeObject) { var sharedTableRootKey = key.FindSharedObjectRootKey(storeObject); return sharedTableRootKey?.IsClustered(storeObject); diff --git a/src/EFCore.SqlServer/Extensions/SqlServerPropertyExtensions.cs b/src/EFCore.SqlServer/Extensions/SqlServerPropertyExtensions.cs index 060e0d6ff47..e0f91a42f11 100644 --- a/src/EFCore.SqlServer/Extensions/SqlServerPropertyExtensions.cs +++ b/src/EFCore.SqlServer/Extensions/SqlServerPropertyExtensions.cs @@ -160,7 +160,7 @@ public static ISequence FindHiLoSequence([NotNull] this IProperty property) /// The property. /// The identifier of the store object. /// The identity seed. - public static int? GetIdentitySeed([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static int? GetIdentitySeed([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { var annotation = property.FindAnnotation(SqlServerAnnotationNames.IdentitySeed); if (annotation != null) @@ -224,7 +224,7 @@ public static void SetIdentitySeed([NotNull] this IMutableProperty property, int /// The property. /// The identifier of the store object. /// The identity increment. - public static int? GetIdentityIncrement([NotNull] this IProperty property, StoreObjectIdentifier storeObject) + public static int? GetIdentityIncrement([NotNull] this IProperty property, in StoreObjectIdentifier storeObject) { var annotation = property.FindAnnotation(SqlServerAnnotationNames.IdentityIncrement); if (annotation != null) @@ -317,7 +317,7 @@ public static SqlServerValueGenerationStrategy GetValueGenerationStrategy([NotNu /// The strategy, or if none was set. public static SqlServerValueGenerationStrategy GetValueGenerationStrategy( [NotNull] this IProperty property, - StoreObjectIdentifier storeObject) + in StoreObjectIdentifier storeObject) { var annotation = property.FindAnnotation(SqlServerAnnotationNames.ValueGenerationStrategy); if (annotation != null) diff --git a/src/EFCore.SqlServer/Internal/SqlServerModelValidator.cs b/src/EFCore.SqlServer/Internal/SqlServerModelValidator.cs index fb33596edde..80fa1831ea4 100644 --- a/src/EFCore.SqlServer/Internal/SqlServerModelValidator.cs +++ b/src/EFCore.SqlServer/Internal/SqlServerModelValidator.cs @@ -230,7 +230,7 @@ protected override void ValidateSharedTableCompatibility( /// protected override void ValidateSharedColumnsCompatibility( IReadOnlyList mappedTypes, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, IDiagnosticsLogger logger) { base.ValidateSharedColumnsCompatibility(mappedTypes, storeObject, logger); @@ -264,7 +264,7 @@ protected override void ValidateCompatible( IProperty property, IProperty duplicateProperty, string columnName, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, IDiagnosticsLogger logger) { base.ValidateCompatible(property, duplicateProperty, columnName, storeObject, logger); @@ -338,7 +338,7 @@ protected override void ValidateCompatible( IKey key, IKey duplicateKey, string keyName, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, IDiagnosticsLogger logger) { base.ValidateCompatible(key, duplicateKey, keyName, storeObject, logger); @@ -351,7 +351,7 @@ protected override void ValidateCompatible( IIndex index, IIndex duplicateIndex, string indexName, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, IDiagnosticsLogger logger) { base.ValidateCompatible(index, duplicateIndex, indexName, storeObject, logger); diff --git a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerSharedTableConvention.cs b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerSharedTableConvention.cs index 1b213d12f12..329bd75cdb5 100644 --- a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerSharedTableConvention.cs +++ b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerSharedTableConvention.cs @@ -31,12 +31,12 @@ public SqlServerSharedTableConvention( } /// - protected override bool AreCompatible(IKey key, IKey duplicateKey, StoreObjectIdentifier storeObject) + protected override bool AreCompatible(IKey key, IKey duplicateKey, in StoreObjectIdentifier storeObject) => base.AreCompatible(key, duplicateKey, storeObject) && key.AreCompatibleForSqlServer(duplicateKey, storeObject, shouldThrow: false); /// - protected override bool AreCompatible(IIndex index, IIndex duplicateIndex, StoreObjectIdentifier storeObject) + protected override bool AreCompatible(IIndex index, IIndex duplicateIndex, in StoreObjectIdentifier storeObject) => base.AreCompatible(index, duplicateIndex, storeObject) && index.AreCompatibleForSqlServer(duplicateIndex, storeObject, shouldThrow: false); } diff --git a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerStoreGenerationConvention.cs b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerStoreGenerationConvention.cs index 72f0599c2e7..f99cd49b5d2 100644 --- a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerStoreGenerationConvention.cs +++ b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerStoreGenerationConvention.cs @@ -97,7 +97,7 @@ public override void ProcessPropertyAnnotationChanged( } /// - protected override void Validate(IConventionProperty property, StoreObjectIdentifier storeObject) + protected override void Validate(IConventionProperty property, in StoreObjectIdentifier storeObject) { if (property.GetValueGenerationStrategyConfigurationSource() != null) { diff --git a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerValueGenerationConvention.cs b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerValueGenerationConvention.cs index f15f394b010..987a2e205f1 100644 --- a/src/EFCore.SqlServer/Metadata/Conventions/SqlServerValueGenerationConvention.cs +++ b/src/EFCore.SqlServer/Metadata/Conventions/SqlServerValueGenerationConvention.cs @@ -75,7 +75,7 @@ public override void ProcessPropertyAnnotationChanged( /// The property. /// The identifier of the store object. /// The store value generation strategy to set for the given property. - public static new ValueGenerated? GetValueGenerated([NotNull] IProperty property, StoreObjectIdentifier storeObject) + public static new ValueGenerated? GetValueGenerated([NotNull] IProperty property, in StoreObjectIdentifier storeObject) => RelationalValueGenerationConvention.GetValueGenerated(property, storeObject) ?? (property.GetValueGenerationStrategy(storeObject) != SqlServerValueGenerationStrategy.None ? ValueGenerated.OnAdd diff --git a/src/EFCore.SqlServer/Metadata/Internal/SqlServerIndexExtensions.cs b/src/EFCore.SqlServer/Metadata/Internal/SqlServerIndexExtensions.cs index b672bda79e6..0bb6170236c 100644 --- a/src/EFCore.SqlServer/Metadata/Internal/SqlServerIndexExtensions.cs +++ b/src/EFCore.SqlServer/Metadata/Internal/SqlServerIndexExtensions.cs @@ -25,19 +25,14 @@ public static class SqlServerIndexExtensions public static bool AreCompatibleForSqlServer( [NotNull] this IIndex index, [NotNull] IIndex duplicateIndex, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, bool shouldThrow) { if (index.GetIncludeProperties() != duplicateIndex.GetIncludeProperties()) { if (index.GetIncludeProperties() == null || duplicateIndex.GetIncludeProperties() == null - || !index.GetIncludeProperties().Select( - p => index.DeclaringEntityType.FindProperty(p).GetColumnName(storeObject)) - .SequenceEqual( - duplicateIndex.GetIncludeProperties().Select( - p => duplicateIndex.DeclaringEntityType.FindProperty(p) - .GetColumnName(storeObject)))) + || !SameColumnNames(index, duplicateIndex, storeObject)) { if (shouldThrow) { @@ -109,6 +104,14 @@ public static bool AreCompatibleForSqlServer( } return true; + + static bool SameColumnNames(IIndex index, IIndex duplicateIndex, StoreObjectIdentifier storeObject) + => index.GetIncludeProperties().Select( + p => index.DeclaringEntityType.FindProperty(p).GetColumnName(storeObject)) + .SequenceEqual( + duplicateIndex.GetIncludeProperties().Select( + p => duplicateIndex.DeclaringEntityType.FindProperty(p) + .GetColumnName(storeObject))); } private static string FormatInclude(IIndex index, StoreObjectIdentifier storeObject) diff --git a/src/EFCore.SqlServer/Metadata/Internal/SqlServerKeyExtensions.cs b/src/EFCore.SqlServer/Metadata/Internal/SqlServerKeyExtensions.cs index eb43fd235e1..e085b056611 100644 --- a/src/EFCore.SqlServer/Metadata/Internal/SqlServerKeyExtensions.cs +++ b/src/EFCore.SqlServer/Metadata/Internal/SqlServerKeyExtensions.cs @@ -24,7 +24,7 @@ public static class SqlServerKeyExtensions public static bool AreCompatibleForSqlServer( [NotNull] this IKey key, [NotNull] IKey duplicateKey, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, bool shouldThrow) { if (key.IsClustered(storeObject) diff --git a/src/EFCore.Sqlite.Core/Extensions/SqlitePropertyExtensions.cs b/src/EFCore.Sqlite.Core/Extensions/SqlitePropertyExtensions.cs index 5e2d62c75ac..610e3e29d8f 100644 --- a/src/EFCore.Sqlite.Core/Extensions/SqlitePropertyExtensions.cs +++ b/src/EFCore.Sqlite.Core/Extensions/SqlitePropertyExtensions.cs @@ -29,7 +29,7 @@ public static class SqlitePropertyExtensions /// The SRID to use when creating a column for this property. public static int? GetSrid( [NotNull] this IProperty property, - StoreObjectIdentifier storeObject) + in StoreObjectIdentifier storeObject) { var annotation = property.FindAnnotation(SqliteAnnotationNames.Srid); if (annotation != null) diff --git a/src/EFCore.Sqlite.Core/Internal/SqliteModelValidator.cs b/src/EFCore.Sqlite.Core/Internal/SqliteModelValidator.cs index 359413d1e8c..964eca6035d 100644 --- a/src/EFCore.Sqlite.Core/Internal/SqliteModelValidator.cs +++ b/src/EFCore.Sqlite.Core/Internal/SqliteModelValidator.cs @@ -93,7 +93,7 @@ protected override void ValidateCompatible( IProperty property, IProperty duplicateProperty, string columnName, - StoreObjectIdentifier storeObject, + in StoreObjectIdentifier storeObject, IDiagnosticsLogger logger) { base.ValidateCompatible(property, duplicateProperty, columnName, storeObject, logger);