From 947fd9d3b0f1016740b1ee74e56ea6ea3da160bb Mon Sep 17 00:00:00 2001 From: lajones Date: Mon, 30 Mar 2020 17:14:15 -0700 Subject: [PATCH] Fixes 20303. Throw in IsUnique if cannot find appropriate NavProp. --- .../Internal/InternalForeignKeyBuilder.cs | 10 ++++ src/EFCore/Properties/CoreStrings.Designer.cs | 8 +++ src/EFCore/Properties/CoreStrings.resx | 3 + .../ModelBuilding/OwnedTypesTestBase.cs | 57 +++++++++++++++---- 4 files changed, 68 insertions(+), 10 deletions(-) diff --git a/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs b/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs index 7f8de4886f6..fb2a290b281 100644 --- a/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs +++ b/src/EFCore/Metadata/Internal/InternalForeignKeyBuilder.cs @@ -1397,6 +1397,16 @@ public virtual InternalForeignKeyBuilder IsUnique(bool? unique, ConfigurationSou return null; } + if (resetToDependent + && Metadata.PrincipalToDependent.GetConfigurationSource() == ConfigurationSource.Explicit) + { + throw new InvalidOperationException( + CoreStrings.UnableToSetIsUnique( + unique.Value, + Metadata.PrincipalToDependent.PropertyInfo.Name, + Metadata.PrincipalEntityType.DisplayName())); + } + using var batch = Metadata.DeclaringEntityType.Model.ConventionDispatcher.DelayConventions(); var builder = this; if (resetToDependent) diff --git a/src/EFCore/Properties/CoreStrings.Designer.cs b/src/EFCore/Properties/CoreStrings.Designer.cs index dab2e1a0d33..94b5bfa8628 100644 --- a/src/EFCore/Properties/CoreStrings.Designer.cs +++ b/src/EFCore/Properties/CoreStrings.Designer.cs @@ -2596,6 +2596,14 @@ public static string QueryEntityMaterializationConditionWrongShape([CanBeNull] o GetString("QueryEntityMaterializationConditionWrongShape", nameof(entityType)), entityType); + /// + /// Unable to set IsUnique to '{isUnique}' on the navigation property '{navigationName}' on the entity type '{entityType}' because the navigation property has the opposite multiplicity.' + /// + public static string UnableToSetIsUnique([CanBeNull] object isUnique, [CanBeNull] object navigationName, [CanBeNull] object entityType) + => string.Format( + GetString("UnableToSetIsUnique", nameof(isUnique), nameof(navigationName), nameof(entityType)), + isUnique, navigationName, entityType); + private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/EFCore/Properties/CoreStrings.resx b/src/EFCore/Properties/CoreStrings.resx index a66b5a6e5f4..a2659268d1a 100644 --- a/src/EFCore/Properties/CoreStrings.resx +++ b/src/EFCore/Properties/CoreStrings.resx @@ -1369,4 +1369,7 @@ Materialization condition passed for entity shaper of entity type '{entityType}' is not of correct shape. Materialization condition must be LambdaExpression of 'Func<ValueBuffer, IEntityType>' + + Unable to set IsUnique to '{isUnique}' on the navigation property '{navigationName}' on the entity type '{entityType}' because the navigation property has the opposite multiplicity.' + \ No newline at end of file diff --git a/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs b/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs index 00766257b37..c896262c5de 100644 --- a/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/OwnedTypesTestBase.cs @@ -190,17 +190,21 @@ public virtual void Changing_ownership_uniqueness_throws() { var modelBuilder = CreateModelBuilder(); - modelBuilder.Entity().OwnsOne( - c => c.Details, - r => - { - r.HasOne(d => d.Customer) - .WithMany(); - }); - Assert.Equal( - CoreStrings.NavigationNotAdded(nameof(Customer), nameof(Customer.Details), nameof(CustomerDetails)), - Assert.Throws(() => modelBuilder.FinalizeModel()).Message); + CoreStrings.UnableToSetIsUnique( + false, + nameof(Customer.Details), + nameof(Customer)), + Assert.Throws( + () => modelBuilder + .Entity() + .OwnsOne( + c => c.Details, + r => + { + r.HasOne(d => d.Customer) + .WithMany(); + })).Message); } [ConditionalFact] @@ -1437,6 +1441,39 @@ public virtual void Navigations_on_OwnsMany_Owned_types_can_set_access_mode_usin Assert.Equal(PropertyAccessMode.Field, principal.FindNavigation("OwnedDependents").GetPropertyAccessMode()); Assert.Equal(PropertyAccessMode.Property, dependent.FindNavigation("OneToManyOwner").GetPropertyAccessMode()); } + + [ConditionalFact] + public virtual void Attempt_to_create_OwnsMany_on_a_reference_throws() + { + var modelBuilder = CreateModelBuilder(); + + Assert.Equal( + CoreStrings.UnableToSetIsUnique( + false, + "OwnedDependent", + typeof(OneToOneNavPrincipalOwner).Name), + Assert.Throws( + () => modelBuilder + .Entity() + .OwnsMany("OwnedDependent")).Message + ); + } + + [ConditionalFact] + public virtual void Attempt_to_create_OwnsOne_on_a_collection_throws() + { + var modelBuilder = CreateModelBuilder(); + + Assert.Equal( + CoreStrings.UnableToSetIsUnique( + true, + "OwnedDependents", + typeof(OneToManyNavPrincipalOwner).Name), + Assert.Throws( + () => modelBuilder + .Entity() + .OwnsOne("OwnedDependents")).Message); + } } } }