From 973cdf42fd38d5914cc191f5df872cca808063fb Mon Sep 17 00:00:00 2001 From: AndriySvyryd Date: Wed, 31 Jul 2019 13:39:45 -0700 Subject: [PATCH] Don't throw exception when NotMapped attribute is overriden by explicit configuration Fixes #16630 --- .../Internal/EntityProjectionExpression.cs | 41 ++++++------------- .../Update/Internal/DocumentSource.cs | 2 +- src/EFCore/Infrastructure/ModelValidator.cs | 5 +++ .../DataAnnotationTestBase.cs | 16 ++++---- .../Internal/InternalEntityTypeBuilderTest.cs | 6 ++- 5 files changed, 29 insertions(+), 41 deletions(-) diff --git a/src/EFCore.Cosmos/Query/Internal/EntityProjectionExpression.cs b/src/EFCore.Cosmos/Query/Internal/EntityProjectionExpression.cs index 0162424df4a..50384104263 100644 --- a/src/EFCore.Cosmos/Query/Internal/EntityProjectionExpression.cs +++ b/src/EFCore.Cosmos/Query/Internal/EntityProjectionExpression.cs @@ -171,32 +171,7 @@ public virtual Expression BindNavigation(INavigation navigation, bool clientEval /// doing so can result in application failures when updating to a new Entity Framework Core release. /// public virtual Expression BindMember(string name, Type entityClrType, bool clientEval, out IPropertyBase propertyBase) - { - var entityType = EntityType; - if (entityClrType != null - && !entityClrType.IsAssignableFrom(entityType.ClrType)) - { - entityType = entityType.GetDerivedTypes().First(e => entityClrType.IsAssignableFrom(e.ClrType)); - } - - var property = entityType.FindProperty(name); - if (property != null) - { - propertyBase = property; - return BindProperty(property, clientEval); - } - - var navigation = entityType.FindNavigation(name); - if (navigation != null) - { - propertyBase = navigation; - return BindNavigation(navigation, clientEval); - } - - // Entity member not found - propertyBase = null; - return null; - } + => BindMember(MemberIdentity.Create(name), entityClrType, clientEval, out propertyBase); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -204,7 +179,11 @@ public virtual Expression BindMember(string name, Type entityClrType, bool clien /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public virtual Expression BindMember(MemberInfo memberInfo, Type entityClrType, bool clientEval, out IPropertyBase propertyBase) + public virtual Expression BindMember( + MemberInfo memberInfo, Type entityClrType, bool clientEval, out IPropertyBase propertyBase) + => BindMember(MemberIdentity.Create(memberInfo), entityClrType, clientEval, out propertyBase); + + private Expression BindMember(MemberIdentity member, Type entityClrType, bool clientEval, out IPropertyBase propertyBase) { var entityType = EntityType; if (entityClrType != null @@ -213,14 +192,18 @@ public virtual Expression BindMember(MemberInfo memberInfo, Type entityClrType, entityType = entityType.GetDerivedTypes().First(e => entityClrType.IsAssignableFrom(e.ClrType)); } - var property = entityType.FindProperty(memberInfo); + var property = member.MemberInfo == null + ? entityType.FindProperty(member.Name) + : entityType.FindProperty(member.MemberInfo); if (property != null) { propertyBase = property; return BindProperty(property, clientEval); } - var navigation = entityType.FindNavigation(memberInfo); + var navigation = member.MemberInfo == null + ? entityType.FindNavigation(member.Name) + : entityType.FindNavigation(member.MemberInfo); if (navigation != null) { propertyBase = navigation; diff --git a/src/EFCore.Cosmos/Update/Internal/DocumentSource.cs b/src/EFCore.Cosmos/Update/Internal/DocumentSource.cs index 55eb47bea39..8d49ae081e5 100644 --- a/src/EFCore.Cosmos/Update/Internal/DocumentSource.cs +++ b/src/EFCore.Cosmos/Update/Internal/DocumentSource.cs @@ -169,7 +169,7 @@ public virtual JObject UpdateDocument(JObject document, IUpdateEntry entry) var embeddedEntry = ((InternalEntityEntry)entry).StateManager.TryGetEntry(embeddedValue, fk.DeclaringEntityType); if (embeddedEntry == null) { - return document; + continue; } var embeddedDocument = embeddedDocumentSource.GetCurrentDocument(embeddedEntry); diff --git a/src/EFCore/Infrastructure/ModelValidator.cs b/src/EFCore/Infrastructure/ModelValidator.cs index 2d505bc1e58..2f2f8a64e48 100644 --- a/src/EFCore/Infrastructure/ModelValidator.cs +++ b/src/EFCore/Infrastructure/ModelValidator.cs @@ -250,6 +250,11 @@ protected virtual void ValidateIgnoredMembers([NotNull] IModel model, [NotNull] { foreach (var ignoredMember in entityType.GetIgnoredMembers()) { + if (entityType.FindIgnoredConfigurationSource(ignoredMember) != ConfigurationSource.Explicit) + { + continue; + } + var property = entityType.FindProperty(ignoredMember); if (property != null) { diff --git a/test/EFCore.Specification.Tests/DataAnnotationTestBase.cs b/test/EFCore.Specification.Tests/DataAnnotationTestBase.cs index 84c7080dd59..ac936de0d85 100644 --- a/test/EFCore.Specification.Tests/DataAnnotationTestBase.cs +++ b/test/EFCore.Specification.Tests/DataAnnotationTestBase.cs @@ -243,13 +243,13 @@ public virtual void NotMapped_on_base_class_property_ignores_it() var modelBuilder = CreateModelBuilder(); modelBuilder.Entity(); - modelBuilder.Entity(); + modelBuilder.Entity().Property(e => e.BaseClassProperty); Validate(modelBuilder); Assert.Null(modelBuilder.Model.FindEntityType(typeof(AbstractBaseEntity1)).FindProperty("BaseClassProperty")); - Assert.Null(modelBuilder.Model.FindEntityType(typeof(BaseEntity1)).FindProperty("BaseClassProperty")); - Assert.Null(modelBuilder.Model.FindEntityType(typeof(Unit1)).FindProperty("BaseClassProperty")); + Assert.NotNull(modelBuilder.Model.FindEntityType(typeof(BaseEntity1)).FindProperty("BaseClassProperty")); + Assert.NotNull(modelBuilder.Model.FindEntityType(typeof(Unit1)).FindProperty("BaseClassProperty")); Assert.Null(modelBuilder.Model.FindEntityType(typeof(AbstractBaseEntity1)).FindProperty("VirtualBaseClassProperty")); Assert.Null(modelBuilder.Model.FindEntityType(typeof(BaseEntity1)).FindProperty("VirtualBaseClassProperty")); Assert.Null(modelBuilder.Model.FindEntityType(typeof(Unit1)).FindProperty("VirtualBaseClassProperty")); @@ -342,18 +342,16 @@ public virtual void NotMapped_on_base_class_property_discovered_through_navigati } [ConditionalFact] - public virtual void NotMapped_on_overridden_mapped_base_class_property_throws() + public virtual void NotMapped_on_overridden_property_is_ignored() { var modelBuilder = CreateModelBuilder(); modelBuilder.Entity(); modelBuilder.Entity(); - Assert.Equal( - CoreStrings.InheritedPropertyCannotBeIgnored( - nameof(Unit3.VirtualBaseClassProperty), typeof(Unit3).ShortDisplayName(), typeof(BaseEntity3).ShortDisplayName()), - Assert.Throws( - () => Validate(modelBuilder)).Message); + Assert.NotNull(modelBuilder.Model.FindEntityType(typeof(Unit3)).FindProperty("VirtualBaseClassProperty")); + + Validate(modelBuilder); } [ConditionalFact] diff --git a/test/EFCore.Tests/Metadata/Internal/InternalEntityTypeBuilderTest.cs b/test/EFCore.Tests/Metadata/Internal/InternalEntityTypeBuilderTest.cs index fe3bd82f0de..803bc9698e5 100644 --- a/test/EFCore.Tests/Metadata/Internal/InternalEntityTypeBuilderTest.cs +++ b/test/EFCore.Tests/Metadata/Internal/InternalEntityTypeBuilderTest.cs @@ -1722,9 +1722,11 @@ private void VerifyIgnoreMember( var addedEntityTypeBuilder = modelBuilder.Entity(typeof(SpecialOrderMinimal), ConfigurationSource.Convention); Assert.False(findMember(addedEntityTypeBuilder)); - var exceptionExpected = ignoredOnType == typeof(ExtraSpecialOrderMinimal); + var exceptionExpected = ignoredOnType == typeof(ExtraSpecialOrderMinimal) + && (ignoreConfigurationSource == ConfigurationSource.Explicit + || (!ignoredFirst && setBaseFirst)); - var expectedAdded = exceptionExpected + var expectedAdded = ignoredOnType == typeof(ExtraSpecialOrderMinimal) || (addConfigurationSource.Overrides(ignoreConfigurationSource) && (ignoreConfigurationSource != ConfigurationSource.Explicit || ignoredOnType != typeof(SpecialOrderMinimal)