From f6d0c6a3912bc705661d92e2e6d70c7e5cb76fd7 Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Fri, 20 Nov 2020 16:05:27 +0200 Subject: [PATCH] Fixups for #23381 and #23376 --- .../Query/Internal/SqlExpressionFactory.cs | 1 - ...yExpressionTranslatingExpressionVisitor.cs | 2 +- ...yableMethodTranslatingExpressionVisitor.cs | 2 +- .../RelationalForeignKeyExtensions.cs | 21 +++++++++++-------- ...yableMethodTranslatingExpressionVisitor.cs | 2 +- ...lationalSqlTranslatingExpressionVisitor.cs | 2 +- src/EFCore/Metadata/Internal/EntityType.cs | 2 +- src/EFCore/Metadata/MemberIdentity.cs | 12 +++++++---- src/EFCore/Properties/CoreStrings.Designer.cs | 6 ++++++ src/EFCore/Properties/CoreStrings.resx | 3 +++ ...ingExpressionVisitor.ExpressionVisitors.cs | 6 ++---- .../CosmosApiConsistencyTest.cs | 7 ------- .../DesignApiConsistencyTest.cs | 7 ------- .../InMemoryApiConsistencyTest.cs | 7 ------- .../ProxiesApiConsistencyTest.cs | 7 ------- .../RelationalApiConsistencyTest.cs | 6 ------ .../ApiConsistencyTestBase.cs | 10 ++++++--- .../SqlServerApiConsistencyTest.cs | 7 ------- .../SqlServerNTSApiConsistencyTest.cs | 7 ------- .../SqliteApiConsistencyTest.cs | 7 ------- .../SqliteNTSApiConsistencyTest.cs | 7 ------- test/EFCore.Tests/ApiConsistencyTest.cs | 6 ------ 22 files changed, 43 insertions(+), 94 deletions(-) diff --git a/src/EFCore.Cosmos/Query/Internal/SqlExpressionFactory.cs b/src/EFCore.Cosmos/Query/Internal/SqlExpressionFactory.cs index 2070f1b9fbc..ebc047a9239 100644 --- a/src/EFCore.Cosmos/Query/Internal/SqlExpressionFactory.cs +++ b/src/EFCore.Cosmos/Query/Internal/SqlExpressionFactory.cs @@ -142,7 +142,6 @@ when sqlUnaryExpression.IsLogicalNot(): throw new InvalidOperationException( CosmosStrings.UnsupportedOperatorForSqlExpression( sqlUnaryExpression.OperatorType, typeof(SqlUnaryExpression).ShortDisplayName())); - ; } return new SqlUnaryExpression(sqlUnaryExpression.OperatorType, operand, resultType, resultTypeMapping); diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs b/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs index b7af450dcd2..63a9ca1400d 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryExpressionTranslatingExpressionVisitor.cs @@ -1117,7 +1117,7 @@ protected override Expression VisitUnary(UnaryExpression unaryExpression) var property = member.MemberInfo != null ? entityType.FindProperty(member.MemberInfo) - : entityType.FindProperty(member.Name!); + : entityType.FindProperty(member.Name); if (property != null) { diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs index 3a47094ab04..8d236186d5a 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs @@ -1390,7 +1390,7 @@ protected override Expression VisitExtension(Expression extensionExpression) var navigation = member.MemberInfo != null ? entityType.FindNavigation(member.MemberInfo) - : entityType.FindNavigation(member.Name!); + : entityType.FindNavigation(member.Name); if (navigation == null) { diff --git a/src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs b/src/EFCore.Relational/Metadata/Internal/RelationalForeignKeyExtensions.cs index 1f8062934f2..e784f74e10f 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; @@ -44,9 +45,7 @@ public static bool AreCompatible( var columnNames = foreignKey.Properties.GetColumnNames(storeObject); var duplicateColumnNames = duplicateForeignKey.Properties.GetColumnNames(storeObject); if (columnNames is null - || duplicateColumnNames is null - || principalTable is null - || duplicatePrincipalTable is null) + || duplicateColumnNames is null) { if (shouldThrow) { @@ -66,11 +65,13 @@ public static bool AreCompatible( return false; } - var principalColumns = foreignKey.PrincipalKey.Properties.GetColumnNames(principalTable.Value); - var duplicatePrincipalColumns = duplicateForeignKey.PrincipalKey.Properties.GetColumnNames(principalTable.Value); - if (principalTable != duplicatePrincipalTable - || principalColumns == null - || duplicatePrincipalColumns == null) + if (principalTable is null + || duplicatePrincipalTable is null + || principalTable != duplicatePrincipalTable + || !(foreignKey.PrincipalKey.Properties.GetColumnNames(principalTable.Value) + is IReadOnlyList principalColumns) + || !(duplicateForeignKey.PrincipalKey.Properties.GetColumnNames(principalTable.Value) + is IReadOnlyList duplicatePrincipalColumns)) { if (shouldThrow) { @@ -81,7 +82,9 @@ public static bool AreCompatible( duplicateForeignKey.Properties.Format(), duplicateForeignKey.DeclaringEntityType.DisplayName(), foreignKey.DeclaringEntityType.GetSchemaQualifiedTableName(), - foreignKey.GetConstraintName(storeObject, principalTable.Value), + principalTable.HasValue + ? foreignKey.GetConstraintName(storeObject, principalTable.Value) + : foreignKey.GetDefaultName(), principalType.GetSchemaQualifiedTableName(), duplicatePrincipalType.GetSchemaQualifiedTableName())); } diff --git a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs index 6733c34d8fc..9b6f171ac03 100644 --- a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs @@ -1340,7 +1340,7 @@ protected override Expression VisitExtension(Expression extensionExpression) var navigation = member.MemberInfo != null ? entityType.FindNavigation(member.MemberInfo) - : entityType.FindNavigation(member.Name!); + : entityType.FindNavigation(member.Name); if (navigation == null) { diff --git a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs index 542bf0241f1..7134f116c78 100644 --- a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs @@ -1077,7 +1077,7 @@ protected override Expression VisitUnary(UnaryExpression unaryExpression) var entityType = entityReferenceExpression.EntityType; var property = member.MemberInfo != null ? entityType.FindProperty(member.MemberInfo) - : entityType.FindProperty(member.Name!); + : entityType.FindProperty(member.Name); if (property != null) { diff --git a/src/EFCore/Metadata/Internal/EntityType.cs b/src/EFCore/Metadata/Internal/EntityType.cs index e91823d1479..31eb3694f9e 100644 --- a/src/EFCore/Metadata/Internal/EntityType.cs +++ b/src/EFCore/Metadata/Internal/EntityType.cs @@ -1502,7 +1502,7 @@ public virtual Navigation AddNavigation( private Navigation AddNavigation(MemberIdentity navigationMember, ForeignKey foreignKey, bool pointsToPrincipal) { - var name = navigationMember.Name!; + var name = navigationMember.Name; var duplicateNavigation = FindNavigationsInHierarchy(name).FirstOrDefault(); if (duplicateNavigation != null) { diff --git a/src/EFCore/Metadata/MemberIdentity.cs b/src/EFCore/Metadata/MemberIdentity.cs index 7d8d8e8f3d9..2bc2d4affa2 100644 --- a/src/EFCore/Metadata/MemberIdentity.cs +++ b/src/EFCore/Metadata/MemberIdentity.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Reflection; using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Diagnostics; #nullable enable @@ -55,7 +56,7 @@ public bool IsNone() /// /// A instance that does not represent any member. /// - public static readonly MemberIdentity None = new MemberIdentity((object?)null); + public static readonly MemberIdentity None = new((object?)null); /// /// Creates a new from the given member name. @@ -78,9 +79,12 @@ public static MemberIdentity Create([CanBeNull] MemberInfo? memberInfo) /// /// The name of the member. /// - public string? Name + /// The is empty. + public string Name { - [DebuggerStepThrough] get => MemberInfo?.GetSimpleMemberName() ?? (string?)_nameOrMember; + [DebuggerStepThrough] get => MemberInfo?.GetSimpleMemberName() + ?? (string?)_nameOrMember + ?? throw new InvalidOperationException(CoreStrings.MemberIdentityIsEmpty); } /// @@ -92,7 +96,7 @@ public MemberInfo? MemberInfo } private string DebuggerDisplay() - => Name ?? "NONE"; + => IsNone() ? "NONE" : Name; /// public override bool Equals(object? obj) diff --git a/src/EFCore/Properties/CoreStrings.Designer.cs b/src/EFCore/Properties/CoreStrings.Designer.cs index cbff7c1336f..8a5e8008487 100644 --- a/src/EFCore/Properties/CoreStrings.Designer.cs +++ b/src/EFCore/Properties/CoreStrings.Designer.cs @@ -1444,6 +1444,12 @@ public static string LiteralGenerationNotSupported([CanBeNull] object type) GetString("LiteralGenerationNotSupported", nameof(type)), type); + /// + /// An empty 'MemberIdentity' has been passed in a context which does not support it. + /// + public static string MemberIdentityIsEmpty + => GetString("MemberIdentityIsEmpty"); + /// /// The specified field '{field}' could not be found for property '{2_entityType}.{1_property}'. /// diff --git a/src/EFCore/Properties/CoreStrings.resx b/src/EFCore/Properties/CoreStrings.resx index 16c1e1dd5d6..3d5bd9a643d 100644 --- a/src/EFCore/Properties/CoreStrings.resx +++ b/src/EFCore/Properties/CoreStrings.resx @@ -959,6 +959,9 @@ '{contextType}' generated value '{keyValue}' for the property '{3_entityType}.{2_property}'. Debug CoreEventId.ValueGenerated string object string string + + An empty 'MemberIdentity' has been passed in a context which does not support it. + The specified field '{field}' could not be found for property '{2_entityType}.{1_property}'. diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs index b106a121cb1..ea94b338492 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs @@ -124,7 +124,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp var navigation = memberIdentity.MemberInfo != null ? entityType.FindNavigation(memberIdentity.MemberInfo) - : entityType.FindNavigation(memberIdentity.Name!); + : entityType.FindNavigation(memberIdentity.Name); if (navigation != null) { return ExpandNavigation(root, entityReference, navigation, convertedType != null); @@ -132,9 +132,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp var skipNavigation = memberIdentity.MemberInfo != null ? entityType.FindSkipNavigation(memberIdentity.MemberInfo) - : memberIdentity.Name is not null - ? entityType.FindSkipNavigation(memberIdentity.Name) - : null; + : entityType.FindSkipNavigation(memberIdentity.Name); if (skipNavigation != null) { return ExpandSkipNavigation(root, entityReference, skipNavigation, convertedType != null); diff --git a/test/EFCore.Cosmos.FunctionalTests/CosmosApiConsistencyTest.cs b/test/EFCore.Cosmos.FunctionalTests/CosmosApiConsistencyTest.cs index 813e6200685..b66fd4fed42 100644 --- a/test/EFCore.Cosmos.FunctionalTests/CosmosApiConsistencyTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/CosmosApiConsistencyTest.cs @@ -27,13 +27,6 @@ protected override Assembly TargetAssembly public class CosmosApiConsistencyFixture : ApiConsistencyFixtureBase { - public override bool TryGetProviderOptionsDelegate(out Action configureOptions) - { - configureOptions = b => CosmosTestHelpers.Instance.UseProviderOptions(b); - - return true; - } - public override HashSet FluentApiTypes { get; } = new HashSet { typeof(CosmosModelBuilderExtensions), diff --git a/test/EFCore.Design.Tests/DesignApiConsistencyTest.cs b/test/EFCore.Design.Tests/DesignApiConsistencyTest.cs index e66b1cf6086..6b0a22c1cc4 100644 --- a/test/EFCore.Design.Tests/DesignApiConsistencyTest.cs +++ b/test/EFCore.Design.Tests/DesignApiConsistencyTest.cs @@ -26,13 +26,6 @@ protected override Assembly TargetAssembly public class DesignApiConsistencyFixture : ApiConsistencyFixtureBase { - public override bool TryGetProviderOptionsDelegate(out Action configureOptions) - { - configureOptions = b => InMemoryTestHelpers.Instance.UseProviderOptions(b); - - return true; - } - public override HashSet FluentApiTypes { get; } = new HashSet { typeof(DesignTimeServiceCollectionExtensions) }; } } diff --git a/test/EFCore.InMemory.FunctionalTests/InMemoryApiConsistencyTest.cs b/test/EFCore.InMemory.FunctionalTests/InMemoryApiConsistencyTest.cs index a9553d31d1d..a74d4e6475d 100644 --- a/test/EFCore.InMemory.FunctionalTests/InMemoryApiConsistencyTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/InMemoryApiConsistencyTest.cs @@ -26,13 +26,6 @@ protected override Assembly TargetAssembly public class InMemoryApiConsistencyFixture : ApiConsistencyFixtureBase { - public override bool TryGetProviderOptionsDelegate(out Action configureOptions) - { - configureOptions = b => InMemoryTestHelpers.Instance.UseProviderOptions(b); - - return true; - } - public override HashSet FluentApiTypes { get; } = new HashSet { typeof(InMemoryServiceCollectionExtensions), diff --git a/test/EFCore.Proxies.Tests/ProxiesApiConsistencyTest.cs b/test/EFCore.Proxies.Tests/ProxiesApiConsistencyTest.cs index 546d7924cb7..f5c40462f60 100644 --- a/test/EFCore.Proxies.Tests/ProxiesApiConsistencyTest.cs +++ b/test/EFCore.Proxies.Tests/ProxiesApiConsistencyTest.cs @@ -24,13 +24,6 @@ protected override Assembly TargetAssembly public class ProxiesApiConsistencyFixture : ApiConsistencyFixtureBase { - public override bool TryGetProviderOptionsDelegate(out Action configureOptions) - { - configureOptions = b => InMemoryTestHelpers.Instance.UseProviderOptions(b); - - return true; - } - public override HashSet FluentApiTypes { get; } = new HashSet { typeof(ProxiesServiceCollectionExtensions) }; } } diff --git a/test/EFCore.Relational.Tests/RelationalApiConsistencyTest.cs b/test/EFCore.Relational.Tests/RelationalApiConsistencyTest.cs index 3a14c662ad5..f82f53745fe 100644 --- a/test/EFCore.Relational.Tests/RelationalApiConsistencyTest.cs +++ b/test/EFCore.Relational.Tests/RelationalApiConsistencyTest.cs @@ -47,12 +47,6 @@ public void Readonly_relational_metadata_methods_have_expected_name() public class RelationalApiConsistencyFixture : ApiConsistencyFixtureBase { - public override bool TryGetProviderOptionsDelegate(out Action configureOptions) - { - configureOptions = null; - return false; - } - private static Dictionary _metadataTypes => new Dictionary { diff --git a/test/EFCore.Specification.Tests/ApiConsistencyTestBase.cs b/test/EFCore.Specification.Tests/ApiConsistencyTestBase.cs index 726d987b1e8..c76e0bb06db 100644 --- a/test/EFCore.Specification.Tests/ApiConsistencyTestBase.cs +++ b/test/EFCore.Specification.Tests/ApiConsistencyTestBase.cs @@ -670,7 +670,13 @@ where ns.StartsWith("Microsoft.Entity", StringComparison.Ordinal) && !it.Name.EndsWith("Dependencies", StringComparison.Ordinal) && (it.GetConstructors().Length != 1 || it.GetConstructors()[0].GetParameters().Length == 0 - || it.GetConstructors()[0].GetParameters()[0].Name != "dependencies") + || it.GetConstructors()[0].GetParameters()[0].Name != "dependencies" + // Check that the parameter has a non-public copy constructor, identifying C# 9 records + || !it.GetConstructors()[0].GetParameters()[0].ParameterType + .GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic) + .Any(c => c.GetParameters() is var parameters + && parameters.Length == 1 + && parameters[0].Name == "original")) select it) .ToList(); @@ -900,8 +906,6 @@ protected ApiConsistencyFixtureBase() Initialize(); } - public abstract bool TryGetProviderOptionsDelegate(out Action configureOptions); - public virtual HashSet FluentApiTypes { get; } = new HashSet(); public virtual Dictionary GenericFluentApiTypes { get; } = new Dictionary diff --git a/test/EFCore.SqlServer.FunctionalTests/SqlServerApiConsistencyTest.cs b/test/EFCore.SqlServer.FunctionalTests/SqlServerApiConsistencyTest.cs index dc985804c16..ff4e8c3ce5d 100644 --- a/test/EFCore.SqlServer.FunctionalTests/SqlServerApiConsistencyTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/SqlServerApiConsistencyTest.cs @@ -28,13 +28,6 @@ protected override Assembly TargetAssembly public class SqlServerApiConsistencyFixture : ApiConsistencyFixtureBase { - public override bool TryGetProviderOptionsDelegate(out Action configureOptions) - { - configureOptions = b => SqlServerTestHelpers.Instance.UseProviderOptions(b); - - return true; - } - public override HashSet FluentApiTypes { get; } = new HashSet { typeof(SqlServerDbContextOptionsBuilder), diff --git a/test/EFCore.SqlServer.Tests/SqlServerNTSApiConsistencyTest.cs b/test/EFCore.SqlServer.Tests/SqlServerNTSApiConsistencyTest.cs index 9d1b0e6a6eb..4581f51dc2e 100644 --- a/test/EFCore.SqlServer.Tests/SqlServerNTSApiConsistencyTest.cs +++ b/test/EFCore.SqlServer.Tests/SqlServerNTSApiConsistencyTest.cs @@ -24,13 +24,6 @@ protected override Assembly TargetAssembly public class SqlServerNTSApiConsistencyFixture : ApiConsistencyFixtureBase { - public override bool TryGetProviderOptionsDelegate(out Action configureOptions) - { - configureOptions = b => SqlServerTestHelpers.Instance.UseProviderOptions(b); - - return true; - } - public override HashSet FluentApiTypes { get; } = new HashSet { typeof(SqlServerNetTopologySuiteDbContextOptionsBuilderExtensions), diff --git a/test/EFCore.Sqlite.FunctionalTests/SqliteApiConsistencyTest.cs b/test/EFCore.Sqlite.FunctionalTests/SqliteApiConsistencyTest.cs index 1f155fca278..91364f8c24e 100644 --- a/test/EFCore.Sqlite.FunctionalTests/SqliteApiConsistencyTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/SqliteApiConsistencyTest.cs @@ -26,13 +26,6 @@ protected override Assembly TargetAssembly public class SqliteApiConsistencyFixture : ApiConsistencyFixtureBase { - public override bool TryGetProviderOptionsDelegate(out Action configureOptions) - { - configureOptions = b => SqliteTestHelpers.Instance.UseProviderOptions(b); - - return true; - } - public override HashSet FluentApiTypes { get; } = new HashSet { typeof(SqliteServiceCollectionExtensions), diff --git a/test/EFCore.Sqlite.Tests/SqliteNTSApiConsistencyTest.cs b/test/EFCore.Sqlite.Tests/SqliteNTSApiConsistencyTest.cs index c2a50878203..55d8bb0e908 100644 --- a/test/EFCore.Sqlite.Tests/SqliteNTSApiConsistencyTest.cs +++ b/test/EFCore.Sqlite.Tests/SqliteNTSApiConsistencyTest.cs @@ -24,13 +24,6 @@ protected override Assembly TargetAssembly public class SqliteNTSApiConsistencyFixture : ApiConsistencyFixtureBase { - public override bool TryGetProviderOptionsDelegate(out Action configureOptions) - { - configureOptions = b => SqliteTestHelpers.Instance.UseProviderOptions(b); - - return true; - } - public override HashSet FluentApiTypes { get; } = new HashSet { typeof(SqliteNetTopologySuiteDbContextOptionsBuilderExtensions), diff --git a/test/EFCore.Tests/ApiConsistencyTest.cs b/test/EFCore.Tests/ApiConsistencyTest.cs index fc558042089..1833bc9358d 100644 --- a/test/EFCore.Tests/ApiConsistencyTest.cs +++ b/test/EFCore.Tests/ApiConsistencyTest.cs @@ -37,12 +37,6 @@ protected override void Initialize() base.Initialize(); } - public override bool TryGetProviderOptionsDelegate(out Action configureOptions) - { - configureOptions = null; - return false; - } - public override HashSet FluentApiTypes { get; } = new HashSet { typeof(ModelBuilder),