diff --git a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs index 1dd039ad979..41db4157cb7 100644 --- a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs +++ b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs @@ -229,7 +229,7 @@ private void SetEntityState(EntityState oldState, EntityState newState, bool acc // ReSharper disable once LoopCanBeConvertedToQuery foreach (var property in entityType.GetProperties()) { - if (HasTemporaryValue(property)) + if (!property.IsForeignKey() && HasTemporaryValue(property)) { throw new InvalidOperationException( CoreStrings.TempValuePersists( diff --git a/test/EFCore.Specification.Tests/StoreGeneratedTestBase.cs b/test/EFCore.Specification.Tests/StoreGeneratedTestBase.cs index 46773825b10..ee4c22c63c8 100644 --- a/test/EFCore.Specification.Tests/StoreGeneratedTestBase.cs +++ b/test/EFCore.Specification.Tests/StoreGeneratedTestBase.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Reflection; using Microsoft.EntityFrameworkCore.Diagnostics; @@ -509,6 +510,59 @@ public virtual void Identity_property_on_Added_entity_with_temporary_value_gets_ context => Assert.Equal("Banana Joe", context.Set().Single(e => e.Id == id).Identity)); } + protected class NonStoreGenDependent + { + [DatabaseGenerated(DatabaseGeneratedOption.None)] + public int Id { get; set; } + public int? StoreGenPrincipalId { get; set; } + public StoreGenPrincipal StoreGenPrincipal { get; set; } + } + + protected class StoreGenPrincipal + { + public int Id { get; set; } + } + + [ConditionalFact] // Issue #22027 + public void Change_state_of_entity_with_temp_FK_does_not_throw() + { + ExecuteWithStrategyInTransaction( + context => + { + var dependent = new NonStoreGenDependent + { + Id = 89, + }; + + context.Add(dependent); + context.SaveChanges(); + }, + context => + { + var principal = new StoreGenPrincipal(); + var dependent = new NonStoreGenDependent + { + Id = 89, + StoreGenPrincipal = principal + }; + + context.Add(dependent); + + context.Entry(dependent).State = EntityState.Modified; + + Assert.Equal(EntityState.Added, context.Entry(principal).State); + Assert.True(context.Entry(principal).Property(e => e.Id).IsTemporary); + Assert.True(context.Entry(dependent).Property(e => e.StoreGenPrincipalId).IsTemporary); + + context.SaveChanges(); + + Assert.Equal(EntityState.Unchanged, context.Entry(principal).State); + Assert.Equal(EntityState.Unchanged, context.Entry(dependent).State); + Assert.False(context.Entry(principal).Property(e => e.Id).IsTemporary); + Assert.False(context.Entry(dependent).Property(e => e.StoreGenPrincipalId).IsTemporary); + }); + } + [ConditionalFact] // Issue #19137 public void Clearing_optional_FK_does_not_leave_temporary_value() { @@ -1856,6 +1910,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con }); modelBuilder.Entity(); + modelBuilder.Entity(); + modelBuilder.Entity(); } } }