From d6b4a52e222dc022d61e32029fa3f0d1147f4d7d Mon Sep 17 00:00:00 2001 From: Andriy Svyryd Date: Tue, 8 Sep 2020 13:21:51 -0700 Subject: [PATCH] Improve exception messages (cont...) Part of #7201 Fixes #18573 --- src/EFCore/Infrastructure/Annotatable.cs | 2 +- .../ForeignKeyAttributeConvention.cs | 3 +- src/EFCore/Metadata/Internal/EntityType.cs | 4 +- src/EFCore/Metadata/Internal/ForeignKey.cs | 2 +- src/EFCore/Properties/CoreStrings.Designer.cs | 40 +++++++++++++------ src/EFCore/Properties/CoreStrings.resx | 16 +++++--- .../DataAnnotationTestBase.cs | 2 +- .../Infrastructure/AnnotatableTest.cs | 2 +- .../Internal/EntityTypeTest.BaseType.cs | 2 +- .../Metadata/Internal/EntityTypeTest.cs | 4 +- 10 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/EFCore/Infrastructure/Annotatable.cs b/src/EFCore/Infrastructure/Annotatable.cs index 84fb08adec4..8314cb8da0f 100644 --- a/src/EFCore/Infrastructure/Annotatable.cs +++ b/src/EFCore/Infrastructure/Annotatable.cs @@ -56,7 +56,7 @@ protected virtual Annotation AddAnnotation([NotNull] string name, [NotNull] Anno { if (FindAnnotation(name) != null) { - throw new InvalidOperationException(CoreStrings.DuplicateAnnotation(name)); + throw new InvalidOperationException(CoreStrings.DuplicateAnnotation(name, ToString())); } SetAnnotation(name, annotation, oldAnnotation: null); diff --git a/src/EFCore/Metadata/Conventions/ForeignKeyAttributeConvention.cs b/src/EFCore/Metadata/Conventions/ForeignKeyAttributeConvention.cs index 45440db5d01..3e29897161e 100644 --- a/src/EFCore/Metadata/Conventions/ForeignKeyAttributeConvention.cs +++ b/src/EFCore/Metadata/Conventions/ForeignKeyAttributeConvention.cs @@ -251,7 +251,8 @@ var fkPropertiesOnDependentToPrincipal throw new InvalidOperationException( CoreStrings.ConflictingForeignKeyAttributes( existingProperties.Format(), - foreignKey.DeclaringEntityType.DisplayName())); + foreignKey.DeclaringEntityType.DisplayName(), + foreignKey.PrincipalEntityType.DisplayName())); } } } diff --git a/src/EFCore/Metadata/Internal/EntityType.cs b/src/EFCore/Metadata/Internal/EntityType.cs index fcdc1b9a975..ae15d4ed158 100644 --- a/src/EFCore/Metadata/Internal/EntityType.cs +++ b/src/EFCore/Metadata/Internal/EntityType.cs @@ -781,7 +781,7 @@ public virtual Key AddKey( { if (property == properties[j]) { - throw new InvalidOperationException(CoreStrings.DuplicatePropertyInList(properties.Format(), property.Name)); + throw new InvalidOperationException(CoreStrings.DuplicatePropertyInKey(properties.Format(), property.Name)); } } @@ -2059,7 +2059,7 @@ private void CheckIndexProperties(IReadOnlyList properties) { if (property == properties[j]) { - throw new InvalidOperationException(CoreStrings.DuplicatePropertyInList(properties.Format(), property.Name)); + throw new InvalidOperationException(CoreStrings.DuplicatePropertyInIndex(properties.Format(), property.Name)); } } diff --git a/src/EFCore/Metadata/Internal/ForeignKey.cs b/src/EFCore/Metadata/Internal/ForeignKey.cs index 59e51abbd84..81dac6bacd2 100644 --- a/src/EFCore/Metadata/Internal/ForeignKey.cs +++ b/src/EFCore/Metadata/Internal/ForeignKey.cs @@ -1204,7 +1204,7 @@ private void Validate( { if (property == properties[j]) { - throw new InvalidOperationException(CoreStrings.DuplicatePropertyInList(properties.Format(), property.Name)); + throw new InvalidOperationException(CoreStrings.DuplicatePropertyInForeignKey(properties.Format(), property.Name)); } } diff --git a/src/EFCore/Properties/CoreStrings.Designer.cs b/src/EFCore/Properties/CoreStrings.Designer.cs index b8363a294fa..7430f889679 100644 --- a/src/EFCore/Properties/CoreStrings.Designer.cs +++ b/src/EFCore/Properties/CoreStrings.Designer.cs @@ -419,12 +419,12 @@ public static string ConflictingBackingFields([CanBeNull] object property, [CanB property, entityType, field1, field2); /// - /// There are multiple [ForeignKey] attributes which are pointing to same set of properties '{propertyList}' on entity type '{entityType}'. + /// There are multiple [ForeignKey] attributes which are pointing to same set of properties '{propertyList}' on entity type '{entityType}' and targeting the principal entity type '{principalEntityType}'. /// - public static string ConflictingForeignKeyAttributes([CanBeNull] object propertyList, [CanBeNull] object entityType) + public static string ConflictingForeignKeyAttributes([CanBeNull] object propertyList, [CanBeNull] object entityType, [CanBeNull] object principalEntityType) => string.Format( - GetString("ConflictingForeignKeyAttributes", nameof(propertyList), nameof(entityType)), - propertyList, entityType); + GetString("ConflictingForeignKeyAttributes", nameof(propertyList), nameof(entityType), nameof(principalEntityType)), + propertyList, entityType, principalEntityType); /// /// The property or navigation '{member}' cannot be added to the entity type '{entityType}' because a property or navigation with the same name already exists on entity type '{conflictingEntityType}'. @@ -619,12 +619,12 @@ public static string DiscriminatorValueIncompatible([CanBeNull] object value, [C value, discriminator, discriminatorType); /// - /// The annotation '{annotation}' cannot be added because an annotation with the same name already exists. + /// The annotation '{annotation}' cannot be added because an annotation with the same name already exists on the object {annotatable} /// - public static string DuplicateAnnotation([CanBeNull] object annotation) + public static string DuplicateAnnotation([CanBeNull] object annotation, [CanBeNull] object annotatable) => string.Format( - GetString("DuplicateAnnotation", nameof(annotation)), - annotation); + GetString("DuplicateAnnotation", nameof(annotation), nameof(annotatable)), + annotation, annotatable); /// /// The discriminator value for '{entityType1}' is '{discriminatorValue}' which is the same for '{entityType2}'. Every concrete entity type in the hierarchy must have a unique discriminator value. @@ -683,11 +683,27 @@ public static string DuplicatePropertiesOnBase([CanBeNull] object entityType, [C entityType, baseType, derivedPropertyType, derivedProperty, basePropertyType, baseProperty); /// - /// The properties {propertyList} cannot be used, because they contain a duplicate: '{property}'. + /// The properties {propertyList} cannot be used for a foreign key, because they contain a duplicate: '{property}'. + /// + public static string DuplicatePropertyInForeignKey([CanBeNull] object propertyList, [CanBeNull] object property) + => string.Format( + GetString("DuplicatePropertyInForeignKey", nameof(propertyList), nameof(property)), + propertyList, property); + + /// + /// The properties {propertyList} cannot be used for an index, because they contain a duplicate: '{property}'. + /// + public static string DuplicatePropertyInIndex([CanBeNull] object propertyList, [CanBeNull] object property) + => string.Format( + GetString("DuplicatePropertyInIndex", nameof(propertyList), nameof(property)), + propertyList, property); + + /// + /// The properties {propertyList} cannot be used for a key, because they contain a duplicate: '{property}'. /// - public static string DuplicatePropertyInList([CanBeNull] object propertyList, [CanBeNull] object property) + public static string DuplicatePropertyInKey([CanBeNull] object propertyList, [CanBeNull] object property) => string.Format( - GetString("DuplicatePropertyInList", nameof(propertyList), nameof(property)), + GetString("DuplicatePropertyInKey", nameof(propertyList), nameof(property)), propertyList, property); /// @@ -1920,7 +1936,7 @@ public static string OwnerlessOwnedType([CanBeNull] object ownedType) ownedType); /// - /// The DbContext of type '{contextType}' cannot be pooled because it does not have a single public constructor accepting a single parameter of type DbContextOptions. + /// The DbContext of type '{contextType}' cannot be pooled because it does not have a public constructor accepting a single parameter of type DbContextOptions or has more than one constructor. /// public static string PoolingContextCtorError([CanBeNull] object contextType) => string.Format( diff --git a/src/EFCore/Properties/CoreStrings.resx b/src/EFCore/Properties/CoreStrings.resx index d1486b88be9..9d3c27e5abc 100644 --- a/src/EFCore/Properties/CoreStrings.resx +++ b/src/EFCore/Properties/CoreStrings.resx @@ -268,7 +268,7 @@ Property '{1_entityType}.{0_property}' matches both '{field1}' and '{field2}' by convention. Explicitly specify the backing field to use with 'HasField' in 'OnModelCreating'. - There are multiple [ForeignKey] attributes which are pointing to same set of properties '{propertyList}' on entity type '{entityType}'. + There are multiple [ForeignKey] attributes which are pointing to same set of properties '{propertyList}' on entity type '{entityType}' and targeting the principal entity type '{principalEntityType}'. The property or navigation '{member}' cannot be added to the entity type '{entityType}' because a property or navigation with the same name already exists on entity type '{conflictingEntityType}'. @@ -346,7 +346,7 @@ Cannot set discriminator value '{value}' for discriminator property '{discriminator}' because it is not assignable to type '{discriminatorType}'. - The annotation '{annotation}' cannot be added because an annotation with the same name already exists. + The annotation '{annotation}' cannot be added because an annotation with the same name already exists on the object {annotatable} The discriminator value for '{entityType1}' is '{discriminatorValue}' which is the same for '{entityType2}'. Every concrete entity type in the hierarchy must have a unique discriminator value. @@ -369,8 +369,14 @@ The type '{entityType}' cannot have base type '{baseType}' because the properties '{derivedPropertyType}.{derivedProperty}' and '{basePropertyType}.{baseProperty}' are conflicting. - - The properties {propertyList} cannot be used, because they contain a duplicate: '{property}'. + + The properties {propertyList} cannot be used for a foreign key, because they contain a duplicate: '{property}'. + + + The properties {propertyList} cannot be used for an index, because they contain a duplicate: '{property}'. + + + The properties {propertyList} cannot be used for a key, because they contain a duplicate: '{property}'. The service property '{property}' of type '{serviceType}' cannot be added to the entity type '{entityType}' because service property '{duplicateName}' of the same type already exists on entity type '{duplicateEntityType}'. @@ -1143,7 +1149,7 @@ The owned entity type '{ownedType}' must be referenced from another entity type via a navigation. Add a navigation to an entity type that points at '{ownedType}'. - The DbContext of type '{contextType}' cannot be pooled because it does not have a single public constructor accepting a single parameter of type DbContextOptions. + The DbContext of type '{contextType}' cannot be pooled because it does not have a public constructor accepting a single parameter of type DbContextOptions or has more than one constructor. 'OnConfiguring' cannot be used to modify DbContextOptions when DbContext pooling is enabled. diff --git a/test/EFCore.Specification.Tests/DataAnnotationTestBase.cs b/test/EFCore.Specification.Tests/DataAnnotationTestBase.cs index ddc860c2cf2..8e1334daf82 100644 --- a/test/EFCore.Specification.Tests/DataAnnotationTestBase.cs +++ b/test/EFCore.Specification.Tests/DataAnnotationTestBase.cs @@ -2175,7 +2175,7 @@ public virtual void ForeignKeyAttribute_throws_if_applied_on_two_relationships_t modelBuilder.Ignore(); Assert.Equal( - CoreStrings.ConflictingForeignKeyAttributes("{'AId'}", nameof(ConflictingFKAttributes)), + CoreStrings.ConflictingForeignKeyAttributes("{'AId'}", nameof(ConflictingFKAttributes), nameof(A)), Assert.Throws(() => modelBuilder.Entity()).Message); } diff --git a/test/EFCore.Tests/Infrastructure/AnnotatableTest.cs b/test/EFCore.Tests/Infrastructure/AnnotatableTest.cs index f13103d074a..d1732d1262f 100644 --- a/test/EFCore.Tests/Infrastructure/AnnotatableTest.cs +++ b/test/EFCore.Tests/Infrastructure/AnnotatableTest.cs @@ -42,7 +42,7 @@ public void Addind_duplicate_annotation_throws() annotatable.AddAnnotation("Foo", "Bar"); Assert.Equal( - CoreStrings.DuplicateAnnotation("Foo"), + CoreStrings.DuplicateAnnotation("Foo", annotatable.ToString()), Assert.Throws(() => annotatable.AddAnnotation("Foo", "Bar")).Message); } diff --git a/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.BaseType.cs b/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.BaseType.cs index 519f9fae192..70d4708fae3 100644 --- a/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.BaseType.cs +++ b/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.BaseType.cs @@ -1122,7 +1122,7 @@ public void Adding_an_index_throws_if_duplicate_properties() var idProperty = entityType.AddProperty(Customer.IdProperty); Assert.Equal( - CoreStrings.DuplicatePropertyInList( + CoreStrings.DuplicatePropertyInIndex( "{'" + Customer.IdProperty.Name + "', '" + Customer.IdProperty.Name + "'}", Customer.IdProperty.Name), Assert.Throws(() => entityType.AddIndex(new[] { idProperty, idProperty })).Message); } diff --git a/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.cs b/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.cs index db29e4daac2..377e1598ed7 100644 --- a/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.cs +++ b/test/EFCore.Tests/Metadata/Internal/EntityTypeTest.cs @@ -344,7 +344,7 @@ public void Adding_a_key_throws_if_duplicated_properties() var idProperty = entityType.AddProperty(Customer.IdProperty); Assert.Equal( - CoreStrings.DuplicatePropertyInList( + CoreStrings.DuplicatePropertyInKey( "{'" + Customer.IdProperty.Name + "', '" + Customer.IdProperty.Name + "'}", Customer.IdProperty.Name), Assert.Throws(() => entityType.AddKey(new[] { idProperty, idProperty })).Message); } @@ -632,7 +632,7 @@ public void Adding_a_foreign_key_throws_if_duplicated_properties() var customerFk1 = orderType.AddProperty(Order.CustomerIdProperty); Assert.Equal( - CoreStrings.DuplicatePropertyInList( + CoreStrings.DuplicatePropertyInForeignKey( "{'" + Order.CustomerIdProperty.Name + "', '" + Order.CustomerIdProperty.Name + "'}", Order.CustomerIdProperty.Name), Assert.Throws(