diff --git a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs index f8003117400..c161a3fca10 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 (!property.IsForeignKey() && HasTemporaryValue(property)) + if (property.IsKey() && HasTemporaryValue(property)) { throw new InvalidOperationException( CoreStrings.TempValuePersists( diff --git a/test/EFCore.Specification.Tests/StoreGeneratedTestBase.cs b/test/EFCore.Specification.Tests/StoreGeneratedTestBase.cs index ee4c22c63c8..a0baaea9cab 100644 --- a/test/EFCore.Specification.Tests/StoreGeneratedTestBase.cs +++ b/test/EFCore.Specification.Tests/StoreGeneratedTestBase.cs @@ -11,6 +11,7 @@ using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Microsoft.EntityFrameworkCore.TestUtilities; +using Microsoft.EntityFrameworkCore.ValueGeneration.Internal; using Xunit; // ReSharper disable InconsistentNaming @@ -515,6 +516,7 @@ protected class NonStoreGenDependent [DatabaseGenerated(DatabaseGeneratedOption.None)] public int Id { get; set; } public int? StoreGenPrincipalId { get; set; } + public int HasTemp { get; set; } public StoreGenPrincipal StoreGenPrincipal { get; set; } } @@ -523,8 +525,10 @@ protected class StoreGenPrincipal public int Id { get; set; } } - [ConditionalFact] // Issue #22027 - public void Change_state_of_entity_with_temp_FK_does_not_throw() + [ConditionalTheory] // Issue #22027 #14192 + [InlineData(EntityState.Modified)] + [InlineData(EntityState.Deleted)] + public void Change_state_of_entity_with_temp_non_key_does_not_throw(EntityState targetState) { ExecuteWithStrategyInTransaction( context => @@ -535,7 +539,13 @@ public void Change_state_of_entity_with_temp_FK_does_not_throw() }; context.Add(dependent); + + Assert.True(context.Entry(dependent).Property(e => e.HasTemp).IsTemporary); + context.SaveChanges(); + + Assert.False(context.Entry(dependent).Property(e => e.HasTemp).IsTemporary); + Assert.Equal(777, dependent.HasTemp); }, context => { @@ -548,17 +558,23 @@ public void Change_state_of_entity_with_temp_FK_does_not_throw() context.Add(dependent); - context.Entry(dependent).State = EntityState.Modified; + context.Entry(dependent).State = targetState; 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.HasTemp).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.Equal( + targetState == EntityState.Modified ? EntityState.Unchanged : EntityState.Detached, + context.Entry(dependent).State); + Assert.False(context.Entry(principal).Property(e => e.Id).IsTemporary); + Assert.False(context.Entry(dependent).Property(e => e.HasTemp).IsTemporary); Assert.False(context.Entry(dependent).Property(e => e.StoreGenPrincipalId).IsTemporary); }); } @@ -1911,7 +1927,11 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con modelBuilder.Entity(); modelBuilder.Entity(); - modelBuilder.Entity(); + + modelBuilder.Entity() + .Property(e => e.HasTemp) + .ValueGeneratedOnAddOrUpdate() + .HasValueGenerator(); } } } diff --git a/test/EFCore.SqlServer.FunctionalTests/StoreGeneratedSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/StoreGeneratedSqlServerTest.cs index c2297e3584a..738f5845398 100644 --- a/test/EFCore.SqlServer.FunctionalTests/StoreGeneratedSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/StoreGeneratedSqlServerTest.cs @@ -195,6 +195,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con b.Property(e => e.NullableBackedIntZeroDefault).HasDefaultValue(0); }); + modelBuilder.Entity().Property(e => e.HasTemp).HasDefaultValue(777); + base.OnModelCreating(modelBuilder, context); } } diff --git a/test/EFCore.Sqlite.FunctionalTests/StoreGeneratedSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/StoreGeneratedSqliteTest.cs index baf6b6f5181..76a2c4d7b04 100644 --- a/test/EFCore.Sqlite.FunctionalTests/StoreGeneratedSqliteTest.cs +++ b/test/EFCore.Sqlite.FunctionalTests/StoreGeneratedSqliteTest.cs @@ -130,6 +130,8 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con .ValueGeneratedOnAdd() .HasDefaultValueSql("randomblob(16)"); + modelBuilder.Entity().Property(e => e.HasTemp).HasDefaultValue(777); + base.OnModelCreating(modelBuilder, context); } }