From 7b69abe7bab16199baf263643ce8734666f5c2dc Mon Sep 17 00:00:00 2001 From: Smit Patel Date: Fri, 17 Sep 2021 12:54:44 -0700 Subject: [PATCH] ModelBuilding: Check for navigation compatibility with keyless type when navigation is non-null Resolves #26073 --- src/EFCore/Metadata/Internal/ForeignKey.cs | 23 +++++++++-------- .../ModelBuilding/OneToManyTestBase.cs | 25 +++++++++++++++++++ test/EFCore.Tests/ModelBuilding/TestModel.cs | 11 ++++++++ 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/EFCore/Metadata/Internal/ForeignKey.cs b/src/EFCore/Metadata/Internal/ForeignKey.cs index 46c5b5f3fe1..42946e8baa4 100644 --- a/src/EFCore/Metadata/Internal/ForeignKey.cs +++ b/src/EFCore/Metadata/Internal/ForeignKey.cs @@ -455,18 +455,21 @@ public virtual void UpdatePrincipalToDependentConfigurationSource(ConfigurationS EnsureMutable(); var name = propertyIdentity?.Name; - if (pointsToPrincipal - && PrincipalEntityType.IsKeyless) + if (name != null) { - throw new InvalidOperationException( - CoreStrings.NavigationToKeylessType(name, PrincipalEntityType.DisplayName())); - } + if (pointsToPrincipal + && PrincipalEntityType.IsKeyless) + { + throw new InvalidOperationException( + CoreStrings.NavigationToKeylessType(name, PrincipalEntityType.DisplayName())); + } - if (!pointsToPrincipal - && DeclaringEntityType.IsKeyless) - { - throw new InvalidOperationException( - CoreStrings.NavigationToKeylessType(name, DeclaringEntityType.DisplayName())); + if (!pointsToPrincipal + && DeclaringEntityType.IsKeyless) + { + throw new InvalidOperationException( + CoreStrings.NavigationToKeylessType(name, DeclaringEntityType.DisplayName())); + } } var oldNavigation = pointsToPrincipal ? DependentToPrincipal : PrincipalToDependent; diff --git a/test/EFCore.Tests/ModelBuilding/OneToManyTestBase.cs b/test/EFCore.Tests/ModelBuilding/OneToManyTestBase.cs index eecc49b0289..7ac7faad3b9 100644 --- a/test/EFCore.Tests/ModelBuilding/OneToManyTestBase.cs +++ b/test/EFCore.Tests/ModelBuilding/OneToManyTestBase.cs @@ -2683,6 +2683,31 @@ public virtual void Navigation_to_shared_type_is_not_discovered_by_convention() CoreStrings.NonConfiguredNavigationToSharedType("Navigation", nameof(CollectionNavigationToSharedType)), Assert.Throws(() => modelBuilder.FinalizeModel()).Message); } + + [ConditionalFact] + public virtual void Reference_navigation_from_keyless_entity_type_works() + { + var modelBuilder = CreateModelBuilder(); + + modelBuilder.Entity(entity => + { + entity.HasNoKey(); + + entity.HasOne(d => d.Store).WithMany(); + }); + + var model = modelBuilder.FinalizeModel(); + + Assert.Collection(model.GetEntityTypes(), + e => + { + Assert.Equal(typeof(Discount).DisplayName(), e.Name); + var fk = Assert.Single(e.GetForeignKeys()); + Assert.False(fk.IsUnique); + Assert.Equal(nameof(Discount.Store), fk.DependentToPrincipal.Name); + }, + e => Assert.Equal(typeof(Store).DisplayName(), e.Name)); + } } } } diff --git a/test/EFCore.Tests/ModelBuilding/TestModel.cs b/test/EFCore.Tests/ModelBuilding/TestModel.cs index 3f33ca6fd0e..7751195a3b4 100644 --- a/test/EFCore.Tests/ModelBuilding/TestModel.cs +++ b/test/EFCore.Tests/ModelBuilding/TestModel.cs @@ -1162,5 +1162,16 @@ protected class Dre protected class DreJr : Dre { } + + protected class Store + { + public int StoreId { get; set; } + } + + protected class Discount + { + public int? StoreId { get; set; } + public Store? Store { get; set; } + } } }