From fd349444c0253d5858a49e55ea00a621d11d64bd Mon Sep 17 00:00:00 2001 From: lajones Date: Mon, 13 Apr 2020 11:01:58 -0700 Subject: [PATCH 1/4] Fix for 15759. Update to error message to include the entity types involved. --- .../Diagnostics/CoreLoggerExtensions.cs | 16 ++++-- ...IncompatibleMatchingForeignKeyEventData.cs | 50 +++++++++++++++++++ .../ForeignKeyPropertyDiscoveryConvention.cs | 3 +- src/EFCore/Properties/CoreStrings.Designer.cs | 10 ++-- src/EFCore/Properties/CoreStrings.resx | 4 +- .../Infrastructure/CoreEventIdTest.cs | 1 + ...reignKeyPropertyDiscoveryConventionTest.cs | 1 + 7 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 src/EFCore/Diagnostics/IncompatibleMatchingForeignKeyEventData.cs diff --git a/src/EFCore/Diagnostics/CoreLoggerExtensions.cs b/src/EFCore/Diagnostics/CoreLoggerExtensions.cs index a64f8d77d93..bf56884edc6 100644 --- a/src/EFCore/Diagnostics/CoreLoggerExtensions.cs +++ b/src/EFCore/Diagnostics/CoreLoggerExtensions.cs @@ -1081,10 +1081,14 @@ private static string RedundantForeignKeyWarning(EventDefinitionBase definition, /// Logs for the event. /// /// The diagnostics logger to use. + /// The entity type on the principal end of the relationship. + /// The entity type on the dependent end of the relationship. /// The properties that make up the foreign key. /// The corresponding keys on the principal side. public static void IncompatibleMatchingForeignKeyProperties( [NotNull] this IDiagnosticsLogger diagnostics, + [NotNull] IConventionEntityType principalEntityType, + [NotNull] IConventionEntityType dependentEntityType, [NotNull] IReadOnlyList foreignKeyProperties, [NotNull] IReadOnlyList principalKeyProperties) { @@ -1094,15 +1098,19 @@ public static void IncompatibleMatchingForeignKeyProperties( { definition.Log( diagnostics, + principalEntityType.DisplayName(), + dependentEntityType.DisplayName(), foreignKeyProperties.Format(includeTypes: true), principalKeyProperties.Format(includeTypes: true)); } if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled)) { - var eventData = new TwoPropertyBaseCollectionsEventData( + var eventData = new IncompatibleMatchingForeignKeyEventData( definition, IncompatibleMatchingForeignKeyProperties, + principalEntityType, + dependentEntityType, foreignKeyProperties, principalKeyProperties); @@ -1112,9 +1120,11 @@ public static void IncompatibleMatchingForeignKeyProperties( private static string IncompatibleMatchingForeignKeyProperties(EventDefinitionBase definition, EventData payload) { - var d = (EventDefinition)definition; - var p = (TwoPropertyBaseCollectionsEventData)payload; + var d = (EventDefinition)definition; + var p = (IncompatibleMatchingForeignKeyEventData)payload; return d.GenerateMessage( + p.PrincipalEntityType.DisplayName(), + p.DependentEntityType.DisplayName(), p.FirstPropertyCollection.Format(includeTypes: true), p.SecondPropertyCollection.Format(includeTypes: true)); } diff --git a/src/EFCore/Diagnostics/IncompatibleMatchingForeignKeyEventData.cs b/src/EFCore/Diagnostics/IncompatibleMatchingForeignKeyEventData.cs new file mode 100644 index 00000000000..799ec04c903 --- /dev/null +++ b/src/EFCore/Diagnostics/IncompatibleMatchingForeignKeyEventData.cs @@ -0,0 +1,50 @@ +// 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.Diagnostics; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore.Metadata; + +namespace Microsoft.EntityFrameworkCore.Diagnostics +{ + /// + /// A event payload class for the + /// IncompatibleMatchingForeignKeyProperties event. + /// + public class IncompatibleMatchingForeignKeyEventData : TwoPropertyBaseCollectionsEventData + { + /// + /// Constructs the event payload. + /// + /// The event definition. + /// A delegate that generates a log message for this event. + /// The entity type on the principal end of the relationship. + /// The entity type on the dependent end of the relationship. + /// The first property collection. + /// The second property collection. + public IncompatibleMatchingForeignKeyEventData( + [NotNull] EventDefinitionBase eventDefinition, + [NotNull] Func messageGenerator, + [NotNull] IConventionEntityType principalEntityType, + [NotNull] IConventionEntityType dependentEntityType, + [NotNull] IReadOnlyList firstPropertyCollection, + [NotNull] IReadOnlyList secondPropertyCollection) + : base(eventDefinition, messageGenerator, firstPropertyCollection, secondPropertyCollection) + { + PrincipalEntityType = principalEntityType; + DependentEntityType = dependentEntityType; + } + + /// + /// The principal entity type. + /// + public virtual IConventionEntityType PrincipalEntityType { get; } + + /// + /// The dependent entity type. + /// + public virtual IConventionEntityType DependentEntityType { get; } + } +} diff --git a/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs index b16ed7004de..1f6a3bb6df2 100644 --- a/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs +++ b/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs @@ -418,7 +418,8 @@ private bool TryFindMatchingProperties( p => !p.IsShadowProperty() || p.GetConfigurationSource().Overrides(ConfigurationSource.DataAnnotation))) { - Dependencies.Logger.IncompatibleMatchingForeignKeyProperties(foreignKeyProperties, propertiesToReference); + Dependencies.Logger.IncompatibleMatchingForeignKeyProperties( + principalEntityType, dependentEntityType, foreignKeyProperties, propertiesToReference); } // Stop searching if match found, but is incompatible diff --git a/src/EFCore/Properties/CoreStrings.Designer.cs b/src/EFCore/Properties/CoreStrings.Designer.cs index 8717cbd083a..5aee8a06359 100644 --- a/src/EFCore/Properties/CoreStrings.Designer.cs +++ b/src/EFCore/Properties/CoreStrings.Designer.cs @@ -3671,27 +3671,27 @@ public static EventDefinition LogRedundantIndexRemoved([ } /// - /// The foreign key properties haven't been configured by convention because the best match {foreignKey} are incompatible with the current principal key {principalKey}. This message can be disregarded if explicit configuration has been specified. + /// For the relationship between principal entity type '{principalEntityType}' and dependent entity type '{dependentEntityType}', the foreign key properties haven't been configured by convention because the best match {foreignKey} are incompatible with the current principal key {principalKey}. This message can be disregarded if explicit configuration has been specified. /// - public static EventDefinition LogIncompatibleMatchingForeignKeyProperties([NotNull] IDiagnosticsLogger logger) + public static EventDefinition LogIncompatibleMatchingForeignKeyProperties([NotNull] IDiagnosticsLogger logger) { var definition = ((LoggingDefinitions)logger.Definitions).LogIncompatibleMatchingForeignKeyProperties; if (definition == null) { definition = LazyInitializer.EnsureInitialized( ref ((LoggingDefinitions)logger.Definitions).LogIncompatibleMatchingForeignKeyProperties, - () => new EventDefinition( + () => new EventDefinition( logger.Options, CoreEventId.IncompatibleMatchingForeignKeyProperties, LogLevel.Debug, "CoreEventId.IncompatibleMatchingForeignKeyProperties", - level => LoggerMessage.Define( + level => LoggerMessage.Define( level, CoreEventId.IncompatibleMatchingForeignKeyProperties, _resourceManager.GetString("LogIncompatibleMatchingForeignKeyProperties")))); } - return (EventDefinition)definition; + return (EventDefinition)definition; } /// diff --git a/src/EFCore/Properties/CoreStrings.resx b/src/EFCore/Properties/CoreStrings.resx index 8e3919f7488..b11411c3131 100644 --- a/src/EFCore/Properties/CoreStrings.resx +++ b/src/EFCore/Properties/CoreStrings.resx @@ -992,8 +992,8 @@ Debug CoreEventId.RedundantIndexRemoved string string string - The foreign key properties haven't been configured by convention because the best match {foreignKey} are incompatible with the current principal key {principalKey}. This message can be disregarded if explicit configuration has been specified. - Debug CoreEventId.IncompatibleMatchingForeignKeyProperties string string + For the relationship between principal entity type '{principalEntityType}' and dependent entity type '{dependentEntityType}', the foreign key properties haven't been configured by convention because the best match {foreignKey} are incompatible with the current principal key {principalKey}. This message can be disregarded if explicit configuration has been specified. + Debug CoreEventId.IncompatibleMatchingForeignKeyProperties string string string string The navigation property '{navigation}' has a RequiredAttribute causing the entity type '{entityType}' to be configured as the dependent side in the corresponding relationship. diff --git a/test/EFCore.Tests/Infrastructure/CoreEventIdTest.cs b/test/EFCore.Tests/Infrastructure/CoreEventIdTest.cs index 2992a1bbbe8..23dd6850ce5 100644 --- a/test/EFCore.Tests/Infrastructure/CoreEventIdTest.cs +++ b/test/EFCore.Tests/Infrastructure/CoreEventIdTest.cs @@ -45,6 +45,7 @@ public void Every_eventId_has_a_logger_method_and_logs_when_level_enabled() { typeof(ExpressionPrinter), () => new ExpressionPrinter() }, { typeof(Expression), () => Expression.Constant("A") }, { typeof(IEntityType), () => entityType }, + { typeof(IConventionEntityType), () => entityType }, { typeof(IKey), () => new Key(new[] { property }, ConfigurationSource.Convention) }, { typeof(IPropertyBase), () => property }, { typeof(IServiceProvider), () => new FakeServiceProvider() }, diff --git a/test/EFCore.Tests/Metadata/Conventions/ForeignKeyPropertyDiscoveryConventionTest.cs b/test/EFCore.Tests/Metadata/Conventions/ForeignKeyPropertyDiscoveryConventionTest.cs index 4c01f3411a3..32427771023 100644 --- a/test/EFCore.Tests/Metadata/Conventions/ForeignKeyPropertyDiscoveryConventionTest.cs +++ b/test/EFCore.Tests/Metadata/Conventions/ForeignKeyPropertyDiscoveryConventionTest.cs @@ -507,6 +507,7 @@ public void Does_not_match_principal_type_plus_PK_name_property_of_different_typ Assert.Equal(LogLevel.Debug, logEntry.Level); Assert.Equal( CoreResources.LogIncompatibleMatchingForeignKeyProperties(new TestLogger()).GenerateMessage( + nameof(PrincipalEntity), nameof(DependentEntity), "{'PrincipalEntityPeeKay' : string}", "{'PeeKay' : int}"), logEntry.Message); ValidateModel(); From cf8f203e9861cc9484a65a737f24b5a8edd2b68e Mon Sep 17 00:00:00 2001 From: lajones Date: Mon, 13 Apr 2020 17:16:51 -0700 Subject: [PATCH 2/4] Updates for review comments. --- .../Diagnostics/CoreLoggerExtensions.cs | 12 +++++------ ...ata.cs => ForeignKeyCandidateEventData.cs} | 20 +++++++++---------- .../ForeignKeyPropertyDiscoveryConvention.cs | 2 +- src/EFCore/Properties/CoreStrings.Designer.cs | 2 +- src/EFCore/Properties/CoreStrings.resx | 2 +- ...reignKeyPropertyDiscoveryConventionTest.cs | 2 +- 6 files changed, 20 insertions(+), 20 deletions(-) rename src/EFCore/Diagnostics/{IncompatibleMatchingForeignKeyEventData.cs => ForeignKeyCandidateEventData.cs} (90%) diff --git a/src/EFCore/Diagnostics/CoreLoggerExtensions.cs b/src/EFCore/Diagnostics/CoreLoggerExtensions.cs index bf56884edc6..7dbf69b89c3 100644 --- a/src/EFCore/Diagnostics/CoreLoggerExtensions.cs +++ b/src/EFCore/Diagnostics/CoreLoggerExtensions.cs @@ -1087,8 +1087,8 @@ private static string RedundantForeignKeyWarning(EventDefinitionBase definition, /// The corresponding keys on the principal side. public static void IncompatibleMatchingForeignKeyProperties( [NotNull] this IDiagnosticsLogger diagnostics, - [NotNull] IConventionEntityType principalEntityType, [NotNull] IConventionEntityType dependentEntityType, + [NotNull] IConventionEntityType principalEntityType, [NotNull] IReadOnlyList foreignKeyProperties, [NotNull] IReadOnlyList principalKeyProperties) { @@ -1098,19 +1098,19 @@ public static void IncompatibleMatchingForeignKeyProperties( { definition.Log( diagnostics, - principalEntityType.DisplayName(), dependentEntityType.DisplayName(), + principalEntityType.DisplayName(), foreignKeyProperties.Format(includeTypes: true), principalKeyProperties.Format(includeTypes: true)); } if (diagnostics.NeedsEventData(definition, out var diagnosticSourceEnabled, out var simpleLogEnabled)) { - var eventData = new IncompatibleMatchingForeignKeyEventData( + var eventData = new ForeignKeyCandidateEventData( definition, IncompatibleMatchingForeignKeyProperties, - principalEntityType, dependentEntityType, + principalEntityType, foreignKeyProperties, principalKeyProperties); @@ -1121,10 +1121,10 @@ public static void IncompatibleMatchingForeignKeyProperties( private static string IncompatibleMatchingForeignKeyProperties(EventDefinitionBase definition, EventData payload) { var d = (EventDefinition)definition; - var p = (IncompatibleMatchingForeignKeyEventData)payload; + var p = (ForeignKeyCandidateEventData)payload; return d.GenerateMessage( - p.PrincipalEntityType.DisplayName(), p.DependentEntityType.DisplayName(), + p.PrincipalEntityType.DisplayName(), p.FirstPropertyCollection.Format(includeTypes: true), p.SecondPropertyCollection.Format(includeTypes: true)); } diff --git a/src/EFCore/Diagnostics/IncompatibleMatchingForeignKeyEventData.cs b/src/EFCore/Diagnostics/ForeignKeyCandidateEventData.cs similarity index 90% rename from src/EFCore/Diagnostics/IncompatibleMatchingForeignKeyEventData.cs rename to src/EFCore/Diagnostics/ForeignKeyCandidateEventData.cs index 799ec04c903..5ed41fe47f3 100644 --- a/src/EFCore/Diagnostics/IncompatibleMatchingForeignKeyEventData.cs +++ b/src/EFCore/Diagnostics/ForeignKeyCandidateEventData.cs @@ -10,10 +10,10 @@ namespace Microsoft.EntityFrameworkCore.Diagnostics { /// - /// A event payload class for the - /// IncompatibleMatchingForeignKeyProperties event. + /// A event payload class for + /// incompatible foreign key properties. /// - public class IncompatibleMatchingForeignKeyEventData : TwoPropertyBaseCollectionsEventData + public class ForeignKeyCandidateEventData : TwoPropertyBaseCollectionsEventData { /// /// Constructs the event payload. @@ -24,27 +24,27 @@ public class IncompatibleMatchingForeignKeyEventData : TwoPropertyBaseCollection /// The entity type on the dependent end of the relationship. /// The first property collection. /// The second property collection. - public IncompatibleMatchingForeignKeyEventData( + public ForeignKeyCandidateEventData( [NotNull] EventDefinitionBase eventDefinition, [NotNull] Func messageGenerator, - [NotNull] IConventionEntityType principalEntityType, [NotNull] IConventionEntityType dependentEntityType, + [NotNull] IConventionEntityType principalEntityType, [NotNull] IReadOnlyList firstPropertyCollection, [NotNull] IReadOnlyList secondPropertyCollection) : base(eventDefinition, messageGenerator, firstPropertyCollection, secondPropertyCollection) { - PrincipalEntityType = principalEntityType; DependentEntityType = dependentEntityType; + PrincipalEntityType = principalEntityType; } /// - /// The principal entity type. + /// The dependent entity type. /// - public virtual IConventionEntityType PrincipalEntityType { get; } + public virtual IConventionEntityType DependentEntityType { get; } /// - /// The dependent entity type. + /// The principal entity type. /// - public virtual IConventionEntityType DependentEntityType { get; } + public virtual IConventionEntityType PrincipalEntityType { get; } } } diff --git a/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs index 1f6a3bb6df2..d86dd384876 100644 --- a/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs +++ b/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs @@ -419,7 +419,7 @@ private bool TryFindMatchingProperties( || p.GetConfigurationSource().Overrides(ConfigurationSource.DataAnnotation))) { Dependencies.Logger.IncompatibleMatchingForeignKeyProperties( - principalEntityType, dependentEntityType, foreignKeyProperties, propertiesToReference); + dependentEntityType, principalEntityType, foreignKeyProperties, propertiesToReference); } // Stop searching if match found, but is incompatible diff --git a/src/EFCore/Properties/CoreStrings.Designer.cs b/src/EFCore/Properties/CoreStrings.Designer.cs index 5aee8a06359..7d16fda6a5e 100644 --- a/src/EFCore/Properties/CoreStrings.Designer.cs +++ b/src/EFCore/Properties/CoreStrings.Designer.cs @@ -3671,7 +3671,7 @@ public static EventDefinition LogRedundantIndexRemoved([ } /// - /// For the relationship between principal entity type '{principalEntityType}' and dependent entity type '{dependentEntityType}', the foreign key properties haven't been configured by convention because the best match {foreignKey} are incompatible with the current principal key {principalKey}. This message can be disregarded if explicit configuration has been specified. + /// For the relationship between dependent entity type '{dependentEntityType}' and principal entity type '{principalEntityType}', the foreign key properties haven't been configured by convention because the best match {foreignKey} are incompatible with the current principal key {principalKey}. This message can be disregarded if explicit configuration has been specified. /// public static EventDefinition LogIncompatibleMatchingForeignKeyProperties([NotNull] IDiagnosticsLogger logger) { diff --git a/src/EFCore/Properties/CoreStrings.resx b/src/EFCore/Properties/CoreStrings.resx index b11411c3131..0e13408c43e 100644 --- a/src/EFCore/Properties/CoreStrings.resx +++ b/src/EFCore/Properties/CoreStrings.resx @@ -992,7 +992,7 @@ Debug CoreEventId.RedundantIndexRemoved string string string - For the relationship between principal entity type '{principalEntityType}' and dependent entity type '{dependentEntityType}', the foreign key properties haven't been configured by convention because the best match {foreignKey} are incompatible with the current principal key {principalKey}. This message can be disregarded if explicit configuration has been specified. + For the relationship between dependent entity type '{dependentEntityType}' and principal entity type '{principalEntityType}', the foreign key properties haven't been configured by convention because the best match {foreignKey} are incompatible with the current principal key {principalKey}. This message can be disregarded if explicit configuration has been specified. Debug CoreEventId.IncompatibleMatchingForeignKeyProperties string string string string diff --git a/test/EFCore.Tests/Metadata/Conventions/ForeignKeyPropertyDiscoveryConventionTest.cs b/test/EFCore.Tests/Metadata/Conventions/ForeignKeyPropertyDiscoveryConventionTest.cs index 32427771023..9fa1226f7df 100644 --- a/test/EFCore.Tests/Metadata/Conventions/ForeignKeyPropertyDiscoveryConventionTest.cs +++ b/test/EFCore.Tests/Metadata/Conventions/ForeignKeyPropertyDiscoveryConventionTest.cs @@ -507,7 +507,7 @@ public void Does_not_match_principal_type_plus_PK_name_property_of_different_typ Assert.Equal(LogLevel.Debug, logEntry.Level); Assert.Equal( CoreResources.LogIncompatibleMatchingForeignKeyProperties(new TestLogger()).GenerateMessage( - nameof(PrincipalEntity), nameof(DependentEntity), + nameof(DependentEntity), nameof(PrincipalEntity), "{'PrincipalEntityPeeKay' : string}", "{'PeeKay' : int}"), logEntry.Message); ValidateModel(); From 64038b7cd745b033b20ad34131a5e8cd1ecc6778 Mon Sep 17 00:00:00 2001 From: lajones Date: Mon, 13 Apr 2020 17:22:57 -0700 Subject: [PATCH 3/4] Switch order of comments too. --- src/EFCore/Diagnostics/CoreLoggerExtensions.cs | 2 +- src/EFCore/Diagnostics/ForeignKeyCandidateEventData.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EFCore/Diagnostics/CoreLoggerExtensions.cs b/src/EFCore/Diagnostics/CoreLoggerExtensions.cs index 7dbf69b89c3..7906075f029 100644 --- a/src/EFCore/Diagnostics/CoreLoggerExtensions.cs +++ b/src/EFCore/Diagnostics/CoreLoggerExtensions.cs @@ -1081,8 +1081,8 @@ private static string RedundantForeignKeyWarning(EventDefinitionBase definition, /// Logs for the event. /// /// The diagnostics logger to use. - /// The entity type on the principal end of the relationship. /// The entity type on the dependent end of the relationship. + /// The entity type on the principal end of the relationship. /// The properties that make up the foreign key. /// The corresponding keys on the principal side. public static void IncompatibleMatchingForeignKeyProperties( diff --git a/src/EFCore/Diagnostics/ForeignKeyCandidateEventData.cs b/src/EFCore/Diagnostics/ForeignKeyCandidateEventData.cs index 5ed41fe47f3..ff7bc8555c8 100644 --- a/src/EFCore/Diagnostics/ForeignKeyCandidateEventData.cs +++ b/src/EFCore/Diagnostics/ForeignKeyCandidateEventData.cs @@ -20,8 +20,8 @@ public class ForeignKeyCandidateEventData : TwoPropertyBaseCollectionsEventData /// /// The event definition. /// A delegate that generates a log message for this event. - /// The entity type on the principal end of the relationship. /// The entity type on the dependent end of the relationship. + /// The entity type on the principal end of the relationship. /// The first property collection. /// The second property collection. public ForeignKeyCandidateEventData( From 1437665aa1fcfd15045c2eb350e91ab5b066f324 Mon Sep 17 00:00:00 2001 From: lajones Date: Mon, 13 Apr 2020 19:02:47 -0700 Subject: [PATCH 4/4] Updating to reference Navigations when we can. --- .../Diagnostics/CoreLoggerExtensions.cs | 20 +++++++++---------- .../ForeignKeyCandidateEventData.cs | 20 +++++++++---------- .../ForeignKeyPropertyDiscoveryConvention.cs | 19 +++++++++++++++++- src/EFCore/Properties/CoreStrings.Designer.cs | 2 +- src/EFCore/Properties/CoreStrings.resx | 2 +- ...reignKeyPropertyDiscoveryConventionTest.cs | 10 +++++++--- 6 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/EFCore/Diagnostics/CoreLoggerExtensions.cs b/src/EFCore/Diagnostics/CoreLoggerExtensions.cs index 7906075f029..c9046172cdf 100644 --- a/src/EFCore/Diagnostics/CoreLoggerExtensions.cs +++ b/src/EFCore/Diagnostics/CoreLoggerExtensions.cs @@ -1081,14 +1081,14 @@ private static string RedundantForeignKeyWarning(EventDefinitionBase definition, /// Logs for the event. /// /// The diagnostics logger to use. - /// The entity type on the dependent end of the relationship. - /// The entity type on the principal end of the relationship. + /// The name of the navigation property or entity type on the dependent end of the relationship. + /// The name of the navigation property or entity type on the principal end of the relationship. /// The properties that make up the foreign key. /// The corresponding keys on the principal side. public static void IncompatibleMatchingForeignKeyProperties( [NotNull] this IDiagnosticsLogger diagnostics, - [NotNull] IConventionEntityType dependentEntityType, - [NotNull] IConventionEntityType principalEntityType, + [NotNull] string dependentToPrincipalNavigationSpecification, + [NotNull] string principalToDependentNavigationSpecification, [NotNull] IReadOnlyList foreignKeyProperties, [NotNull] IReadOnlyList principalKeyProperties) { @@ -1098,8 +1098,8 @@ public static void IncompatibleMatchingForeignKeyProperties( { definition.Log( diagnostics, - dependentEntityType.DisplayName(), - principalEntityType.DisplayName(), + dependentToPrincipalNavigationSpecification, + principalToDependentNavigationSpecification, foreignKeyProperties.Format(includeTypes: true), principalKeyProperties.Format(includeTypes: true)); } @@ -1109,8 +1109,8 @@ public static void IncompatibleMatchingForeignKeyProperties( var eventData = new ForeignKeyCandidateEventData( definition, IncompatibleMatchingForeignKeyProperties, - dependentEntityType, - principalEntityType, + dependentToPrincipalNavigationSpecification, + principalToDependentNavigationSpecification, foreignKeyProperties, principalKeyProperties); @@ -1123,8 +1123,8 @@ private static string IncompatibleMatchingForeignKeyProperties(EventDefinitionBa var d = (EventDefinition)definition; var p = (ForeignKeyCandidateEventData)payload; return d.GenerateMessage( - p.DependentEntityType.DisplayName(), - p.PrincipalEntityType.DisplayName(), + p.DependentToPrincipalNavigationSpecification, + p.PrincipalToDependentNavigationSpecification, p.FirstPropertyCollection.Format(includeTypes: true), p.SecondPropertyCollection.Format(includeTypes: true)); } diff --git a/src/EFCore/Diagnostics/ForeignKeyCandidateEventData.cs b/src/EFCore/Diagnostics/ForeignKeyCandidateEventData.cs index ff7bc8555c8..29c70cb6950 100644 --- a/src/EFCore/Diagnostics/ForeignKeyCandidateEventData.cs +++ b/src/EFCore/Diagnostics/ForeignKeyCandidateEventData.cs @@ -20,31 +20,31 @@ public class ForeignKeyCandidateEventData : TwoPropertyBaseCollectionsEventData /// /// The event definition. /// A delegate that generates a log message for this event. - /// The entity type on the dependent end of the relationship. - /// The entity type on the principal end of the relationship. + /// The name of the navigation property or entity type on the dependent end of the relationship. + /// The name of the navigation property or entity type on the principal end of the relationship. /// The first property collection. /// The second property collection. public ForeignKeyCandidateEventData( [NotNull] EventDefinitionBase eventDefinition, [NotNull] Func messageGenerator, - [NotNull] IConventionEntityType dependentEntityType, - [NotNull] IConventionEntityType principalEntityType, + [NotNull] string dependentToPrincipalNavigationSpecification, + [NotNull] string principalToDependentNavigationSpecification, [NotNull] IReadOnlyList firstPropertyCollection, [NotNull] IReadOnlyList secondPropertyCollection) : base(eventDefinition, messageGenerator, firstPropertyCollection, secondPropertyCollection) { - DependentEntityType = dependentEntityType; - PrincipalEntityType = principalEntityType; + DependentToPrincipalNavigationSpecification = dependentToPrincipalNavigationSpecification; + PrincipalToDependentNavigationSpecification = principalToDependentNavigationSpecification; } /// - /// The dependent entity type. + /// The name of the navigation property or entity type on the dependent end of the relationship. /// - public virtual IConventionEntityType DependentEntityType { get; } + public virtual string DependentToPrincipalNavigationSpecification { get; } /// - /// The principal entity type. + /// The name of the navigation property or entity type on the principal end of the relationship. /// - public virtual IConventionEntityType PrincipalEntityType { get; } + public virtual string PrincipalToDependentNavigationSpecification { get; } } } diff --git a/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs b/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs index d86dd384876..43280026618 100644 --- a/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs +++ b/src/EFCore/Metadata/Conventions/ForeignKeyPropertyDiscoveryConvention.cs @@ -418,8 +418,25 @@ private bool TryFindMatchingProperties( p => !p.IsShadowProperty() || p.GetConfigurationSource().Overrides(ConfigurationSource.DataAnnotation))) { + var dependentNavigationSpec = onDependent + ? foreignKey.DependentToPrincipal?.Name + : foreignKey.PrincipalToDependent?.Name; + dependentNavigationSpec = dependentEntityType.DisplayName() + + (string.IsNullOrEmpty(dependentNavigationSpec) + ? string.Empty + : "." + dependentNavigationSpec); + + var principalNavigationSpec = onDependent + ? foreignKey.PrincipalToDependent?.Name + : foreignKey.DependentToPrincipal?.Name; + principalNavigationSpec = principalEntityType.DisplayName() + + (string.IsNullOrEmpty(principalNavigationSpec) + ? string.Empty + : "." + principalNavigationSpec); + Dependencies.Logger.IncompatibleMatchingForeignKeyProperties( - dependentEntityType, principalEntityType, foreignKeyProperties, propertiesToReference); + dependentNavigationSpec, principalNavigationSpec, + foreignKeyProperties, propertiesToReference); } // Stop searching if match found, but is incompatible diff --git a/src/EFCore/Properties/CoreStrings.Designer.cs b/src/EFCore/Properties/CoreStrings.Designer.cs index 7d16fda6a5e..cf4bafc35de 100644 --- a/src/EFCore/Properties/CoreStrings.Designer.cs +++ b/src/EFCore/Properties/CoreStrings.Designer.cs @@ -3671,7 +3671,7 @@ public static EventDefinition LogRedundantIndexRemoved([ } /// - /// For the relationship between dependent entity type '{dependentEntityType}' and principal entity type '{principalEntityType}', the foreign key properties haven't been configured by convention because the best match {foreignKey} are incompatible with the current principal key {principalKey}. This message can be disregarded if explicit configuration has been specified. + /// For the relationship between dependent '{dependentToPrincipalNavigationSpecification}' and principal '{principalToDependentNavigationSpecification}', the foreign key properties haven't been configured by convention because the best match {foreignKey} are incompatible with the current principal key {principalKey}. This message can be disregarded if explicit configuration has been specified. /// public static EventDefinition LogIncompatibleMatchingForeignKeyProperties([NotNull] IDiagnosticsLogger logger) { diff --git a/src/EFCore/Properties/CoreStrings.resx b/src/EFCore/Properties/CoreStrings.resx index 0e13408c43e..76248cb542f 100644 --- a/src/EFCore/Properties/CoreStrings.resx +++ b/src/EFCore/Properties/CoreStrings.resx @@ -992,7 +992,7 @@ Debug CoreEventId.RedundantIndexRemoved string string string - For the relationship between dependent entity type '{dependentEntityType}' and principal entity type '{principalEntityType}', the foreign key properties haven't been configured by convention because the best match {foreignKey} are incompatible with the current principal key {principalKey}. This message can be disregarded if explicit configuration has been specified. + For the relationship between dependent '{dependentToPrincipalNavigationSpecification}' and principal '{principalToDependentNavigationSpecification}', the foreign key properties haven't been configured by convention because the best match {foreignKey} are incompatible with the current principal key {principalKey}. This message can be disregarded if explicit configuration has been specified. Debug CoreEventId.IncompatibleMatchingForeignKeyProperties string string string string diff --git a/test/EFCore.Tests/Metadata/Conventions/ForeignKeyPropertyDiscoveryConventionTest.cs b/test/EFCore.Tests/Metadata/Conventions/ForeignKeyPropertyDiscoveryConventionTest.cs index 9fa1226f7df..9dbf2005808 100644 --- a/test/EFCore.Tests/Metadata/Conventions/ForeignKeyPropertyDiscoveryConventionTest.cs +++ b/test/EFCore.Tests/Metadata/Conventions/ForeignKeyPropertyDiscoveryConventionTest.cs @@ -506,9 +506,13 @@ public void Does_not_match_principal_type_plus_PK_name_property_of_different_typ var logEntry = ListLoggerFactory.Log.Single(); Assert.Equal(LogLevel.Debug, logEntry.Level); Assert.Equal( - CoreResources.LogIncompatibleMatchingForeignKeyProperties(new TestLogger()).GenerateMessage( - nameof(DependentEntity), nameof(PrincipalEntity), - "{'PrincipalEntityPeeKay' : string}", "{'PeeKay' : int}"), logEntry.Message); + CoreResources.LogIncompatibleMatchingForeignKeyProperties( + new TestLogger()).GenerateMessage( + nameof(DependentEntity) + "." + nameof(DependentEntity.SomeNav), + nameof(PrincipalEntity), + "{'PrincipalEntityPeeKay' : string}", + "{'PeeKay' : int}"), + logEntry.Message); ValidateModel(); }