diff --git a/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs b/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs index 632d38a8bd6..8352c7f721f 100644 --- a/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs @@ -41,7 +41,7 @@ public static string GetDefaultTableName([NotNull] this IEntityType entityType) return ownership.PrincipalEntityType.GetTableName(); } - return IdentifierHelpers.Truncate( + return Uniquifier.Truncate( entityType.HasDefiningNavigation() ? $"{entityType.DefiningEntityType.GetTableName()}_{entityType.DefiningNavigationName}" : entityType.ShortName(), diff --git a/src/EFCore.Relational/Extensions/RelationalForeignKeyExtensions.cs b/src/EFCore.Relational/Extensions/RelationalForeignKeyExtensions.cs index f869b6b2e27..53c0e0b158c 100644 --- a/src/EFCore.Relational/Extensions/RelationalForeignKeyExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalForeignKeyExtensions.cs @@ -41,7 +41,7 @@ public static string GetDefaultName([NotNull] this IForeignKey foreignKey) .AppendJoin(foreignKey.Properties.Select(p => p.GetColumnName()), "_") .ToString(); - return IdentifierHelpers.Truncate(baseName, foreignKey.DeclaringEntityType.Model.GetMaxIdentifierLength()); + return Uniquifier.Truncate(baseName, foreignKey.DeclaringEntityType.Model.GetMaxIdentifierLength()); } /// diff --git a/src/EFCore.Relational/Extensions/RelationalIndexExtensions.cs b/src/EFCore.Relational/Extensions/RelationalIndexExtensions.cs index 2bf55a8c032..5605eaaf79b 100644 --- a/src/EFCore.Relational/Extensions/RelationalIndexExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalIndexExtensions.cs @@ -39,7 +39,7 @@ public static string GetDefaultName([NotNull] this IIndex index) .AppendJoin(index.Properties.Select(p => p.GetColumnName()), "_") .ToString(); - return IdentifierHelpers.Truncate(baseName, index.DeclaringEntityType.Model.GetMaxIdentifierLength()); + return Uniquifier.Truncate(baseName, index.DeclaringEntityType.Model.GetMaxIdentifierLength()); } /// diff --git a/src/EFCore.Relational/Extensions/RelationalKeyExtensions.cs b/src/EFCore.Relational/Extensions/RelationalKeyExtensions.cs index 98986f90e11..e7581d6978b 100644 --- a/src/EFCore.Relational/Extensions/RelationalKeyExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalKeyExtensions.cs @@ -57,7 +57,7 @@ public static string GetDefaultName([NotNull] this IKey key) .AppendJoin(key.Properties.Select(p => p.GetColumnName()), "_"); } - return IdentifierHelpers.Truncate(builder.ToString(), key.DeclaringEntityType.Model.GetMaxIdentifierLength()); + return Uniquifier.Truncate(builder.ToString(), key.DeclaringEntityType.Model.GetMaxIdentifierLength()); } /// diff --git a/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs b/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs index ca0e2c240ed..c9eeb4b405b 100644 --- a/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs @@ -85,7 +85,7 @@ public static string GetDefaultColumnName([NotNull] this IProperty property) baseName = builder.ToString(); } - return IdentifierHelpers.Truncate(baseName, property.DeclaringEntityType.Model.GetMaxIdentifierLength()); + return Uniquifier.Truncate(baseName, property.DeclaringEntityType.Model.GetMaxIdentifierLength()); } /// diff --git a/src/EFCore.Relational/Metadata/Conventions/SharedTableConvention.cs b/src/EFCore.Relational/Metadata/Conventions/SharedTableConvention.cs index 00f553c4cfb..a99efd10fa0 100644 --- a/src/EFCore.Relational/Metadata/Conventions/SharedTableConvention.cs +++ b/src/EFCore.Relational/Metadata/Conventions/SharedTableConvention.cs @@ -93,7 +93,7 @@ private static void TryUniquifyTableNames( { if (entityType[RelationalAnnotationNames.TableName] == null) { - var uniqueName = IdentifierHelpers.Uniquify( + var uniqueName = Uniquifier.Uniquify( tableName.TableName, tables, n => (tableName.Schema, n), maxLength); if (entityType.Builder.ToTable(uniqueName) != null) { @@ -110,7 +110,7 @@ private static void TryUniquifyTableNames( var otherEntityType = entityTypes.First(); if (otherEntityType[RelationalAnnotationNames.TableName] == null) { - var uniqueName = IdentifierHelpers.Uniquify( + var uniqueName = Uniquifier.Uniquify( tableName.TableName, tables, n => (tableName.Schema, n), maxLength); if (otherEntityType.Builder.ToTable(uniqueName) != null) { @@ -213,7 +213,7 @@ private static string TryUniquify( } } - columnName = IdentifierHelpers.Uniquify(columnName, properties, maxLength); + columnName = Uniquifier.Uniquify(columnName, properties, maxLength); property.Builder.HasColumnName(columnName); properties[columnName] = property; return columnName; @@ -260,7 +260,7 @@ private static string TryUniquify( { if (key.Builder.CanSetName(null)) { - keyName = IdentifierHelpers.Uniquify(keyName, keys, maxLength); + keyName = Uniquifier.Uniquify(keyName, keys, maxLength); key.Builder.HasName(keyName); return keyName; } @@ -316,7 +316,7 @@ private static string TryUniquify( { if (index.Builder.CanSetName(null)) { - indexName = IdentifierHelpers.Uniquify(indexName, indexes, maxLength); + indexName = Uniquifier.Uniquify(indexName, indexes, maxLength); index.Builder.HasName(indexName); return indexName; } @@ -375,7 +375,7 @@ private static string TryUniquify( { if (foreignKey.Builder.CanSetConstraintName(null)) { - foreignKeyName = IdentifierHelpers.Uniquify(foreignKeyName, foreignKeys, maxLength); + foreignKeyName = Uniquifier.Uniquify(foreignKeyName, foreignKeys, maxLength); foreignKey.Builder.HasConstraintName(foreignKeyName); return foreignKeyName; } diff --git a/src/EFCore/Infrastructure/IdentifierHelpers.cs b/src/EFCore/Infrastructure/Uniquifier.cs similarity index 99% rename from src/EFCore/Infrastructure/IdentifierHelpers.cs rename to src/EFCore/Infrastructure/Uniquifier.cs index 62b966b06b2..1c4aa34d507 100644 --- a/src/EFCore/Infrastructure/IdentifierHelpers.cs +++ b/src/EFCore/Infrastructure/Uniquifier.cs @@ -11,7 +11,7 @@ namespace Microsoft.EntityFrameworkCore.Infrastructure /// /// Provides methods for manipulating string identifiers. /// - public static class IdentifierHelpers + public static class Uniquifier { /// /// Creates a unique identifier by appending a number to the given string. diff --git a/src/EFCore/Metadata/IConstructorBindingFactory.cs b/src/EFCore/Metadata/IConstructorBindingFactory.cs index c3dda64e9bc..44348162488 100644 --- a/src/EFCore/Metadata/IConstructorBindingFactory.cs +++ b/src/EFCore/Metadata/IConstructorBindingFactory.cs @@ -36,5 +36,21 @@ bool TryBindConstructor( [NotNull] ConstructorInfo constructor, [CanBeNull] out InstantiationBinding binding, [CanBeNull] out IEnumerable unboundParameters); + + /// + /// Attempts to create a for the given and + /// + /// + /// The entity type. + /// The constructor to use. + /// The binding, or null if null could be created. + /// The parameters that could not be bound. + /// true if a binding was created; false otherwise. + [ContractAnnotation("=>true, binding:notnull, failedBindings:null; =>false, binding:null, failedBindings:notnull")] + bool TryBindConstructor( + [NotNull] IMutableEntityType entityType, + [NotNull] ConstructorInfo constructor, + [CanBeNull] out InstantiationBinding binding, + [CanBeNull] out IEnumerable unboundParameters); } } diff --git a/src/EFCore/Metadata/IPropertyParameterBindingFactory.cs b/src/EFCore/Metadata/IPropertyParameterBindingFactory.cs index be580b87be6..34801e8b433 100644 --- a/src/EFCore/Metadata/IPropertyParameterBindingFactory.cs +++ b/src/EFCore/Metadata/IPropertyParameterBindingFactory.cs @@ -27,7 +27,7 @@ public interface IPropertyParameterBindingFactory /// The parameter name. /// The parameter type. /// The parameter binding, or null if none was found. - ParameterBinding TryBindParameter( + ParameterBinding FindParameter( [NotNull] IEntityType entityType, [NotNull] Type parameterType, [NotNull] string parameterName); diff --git a/src/EFCore/Metadata/Internal/ConstructorBindingFactory.cs b/src/EFCore/Metadata/Internal/ConstructorBindingFactory.cs index ae278d2a347..2ca3f378b1e 100644 --- a/src/EFCore/Metadata/Internal/ConstructorBindingFactory.cs +++ b/src/EFCore/Metadata/Internal/ConstructorBindingFactory.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // 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 System.Reflection; @@ -41,6 +42,24 @@ public ConstructorBindingFactory( _factories = factories; } + /// + /// 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 TryBindConstructor( + IMutableEntityType entityType, + ConstructorInfo constructor, + out InstantiationBinding binding, + out IEnumerable unboundParameters) + => TryBindConstructor( + entityType, + constructor, + (f, e, p, n) => f?.Bind((IMutableEntityType)e, p, n), + out binding, + out unboundParameters); + /// /// 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 @@ -52,11 +71,24 @@ public virtual bool TryBindConstructor( ConstructorInfo constructor, out InstantiationBinding binding, out IEnumerable unboundParameters) + => TryBindConstructor( + entityType, + constructor, + (f, e, p, n) => f?.Bind((IConventionEntityType)e, p, n), + out binding, + out unboundParameters); + + private bool TryBindConstructor( + IEntityType entityType, + ConstructorInfo constructor, + Func bind, + out InstantiationBinding binding, + out IEnumerable unboundParameters) { IEnumerable<(ParameterInfo Parameter, ParameterBinding Binding)> bindings = constructor.GetParameters().Select( - p => (p, _propertyFactory.TryBindParameter(entityType, p.ParameterType, p.Name) - ?? _factories.FindFactory(p.ParameterType, p.Name)?.Bind(entityType, p.ParameterType, p.Name))) + p => (p, _propertyFactory.FindParameter(entityType, p.ParameterType, p.Name) + ?? bind(_factories.FindFactory(p.ParameterType, p.Name), entityType, p.ParameterType, p.Name))) .ToList(); if (bindings.Any(b => b.Binding == null)) diff --git a/src/EFCore/Metadata/Internal/PropertyParameterBindingFactory.cs b/src/EFCore/Metadata/Internal/PropertyParameterBindingFactory.cs index e88b24be812..5def47fa48a 100644 --- a/src/EFCore/Metadata/Internal/PropertyParameterBindingFactory.cs +++ b/src/EFCore/Metadata/Internal/PropertyParameterBindingFactory.cs @@ -29,7 +29,7 @@ public class PropertyParameterBindingFactory : IPropertyParameterBindingFactory /// 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 ParameterBinding TryBindParameter( + public virtual ParameterBinding FindParameter( IEntityType entityType, Type parameterType, string parameterName)