diff --git a/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs b/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs index 2de8e7c293a..e7dd8f1ad16 100644 --- a/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs +++ b/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs @@ -831,6 +831,8 @@ private void InitialFixup( AddToCollection(otherEntry, skipNavigation.Inverse, entry, fromQuery); } + + entry.AddToCollectionSnapshot(skipNavigation, otherEntity); } } } diff --git a/test/EFCore.Specification.Tests/ManyToManyTrackingTestBase.cs b/test/EFCore.Specification.Tests/ManyToManyTrackingTestBase.cs index e9560a90d91..1314f9dda25 100644 --- a/test/EFCore.Specification.Tests/ManyToManyTrackingTestBase.cs +++ b/test/EFCore.Specification.Tests/ManyToManyTrackingTestBase.cs @@ -8,6 +8,8 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.TestModels.ManyToManyModel; @@ -113,7 +115,7 @@ await ExecuteWithStrategyInTransactionAsync( ValidateFixup(context, leftEntities, rightEntities); }); - static void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) + void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) { Assert.Equal(11, context.ChangeTracker.Entries().Count()); Assert.Equal(3, context.ChangeTracker.Entries().Count()); @@ -128,7 +130,8 @@ static void ValidateFixup(DbContext context, IList leftEntit Assert.Single(rightEntities[1].CompositeKeySkipFull); Assert.Single(rightEntities[2].CompositeKeySkipFull); - foreach (var joinEntity in context.ChangeTracker.Entries().Select(e => e.Entity).ToList()) + var joinEntities = context.ChangeTracker.Entries().Select(e => e.Entity).ToList(); + foreach (var joinEntity in joinEntities) { Assert.Equal(joinEntity.Composite.Key1, joinEntity.CompositeId1); Assert.Equal(joinEntity.Composite.Key2, joinEntity.CompositeId2); @@ -138,6 +141,10 @@ static void ValidateFixup(DbContext context, IList leftEntit Assert.Contains(joinEntity, joinEntity.Composite.JoinLeafFull); Assert.Contains(joinEntity, joinEntity.Leaf.JoinCompositeKeyFull); } + + VerifyRelationshipSnapshots(context, joinEntities); + VerifyRelationshipSnapshots(context, leftEntities); + VerifyRelationshipSnapshots(context, rightEntities); } } @@ -242,7 +249,7 @@ public virtual void Can_update_many_to_many_composite_with_navs() ValidateFixup(context, leftEntities, rightEntities, 24, 8, 39 - 4); }); - static void ValidateFixup( + void ValidateFixup( DbContext context, List leftEntities, List rightEntities, @@ -272,7 +279,8 @@ static void ValidateFixup( Assert.DoesNotContain(rightEntities[2].CompositeKeySkipFull, e => e.Key2 == "8_1"); Assert.Contains(rightEntities[2].CompositeKeySkipFull, e => e.Key2 == "7714"); - foreach (var joinEntry in context.ChangeTracker.Entries().ToList()) + var joinEntries = context.ChangeTracker.Entries().ToList(); + foreach (var joinEntry in joinEntries) { var joinEntity = joinEntry.Entity; @@ -288,6 +296,10 @@ static void ValidateFixup( var allLeft = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Key2).ToList(); var allRight = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); + VerifyRelationshipSnapshots(context, joinEntries.Select(e => e.Entity)); + VerifyRelationshipSnapshots(context, allLeft); + VerifyRelationshipSnapshots(context, allRight); + var count = 0; foreach (var left in allLeft) { @@ -565,7 +577,7 @@ await ExecuteWithStrategyInTransactionAsync( ValidateFixup(context, leftEntities, rightEntities); }); - static void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) + void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) { Assert.Equal(11, context.ChangeTracker.Entries().Count()); Assert.Equal(3, context.ChangeTracker.Entries().Count()); @@ -579,6 +591,9 @@ static void ValidateFixup(DbContext context, IList leftEntit Assert.Equal(3, rightEntities[0].CompositeKeySkipShared.Count); Assert.Single(rightEntities[1].CompositeKeySkipShared); Assert.Single(rightEntities[2].CompositeKeySkipShared); + + VerifyRelationshipSnapshots(context, leftEntities); + VerifyRelationshipSnapshots(context, rightEntities); } } @@ -723,6 +738,9 @@ void ValidateFixup( var allLeft = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Key2).ToList(); var allRight = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); + VerifyRelationshipSnapshots(context, allLeft); + VerifyRelationshipSnapshots(context, allRight); + var count = 0; foreach (var left in allLeft) { @@ -935,7 +953,7 @@ await ExecuteWithStrategyInTransactionAsync( context.AddRange(rightEntities[0], rightEntities[1], rightEntities[2]); } - ValidateFixup(context, leftEntities, rightEntities); + ValidateFixup(context, leftEntities, rightEntities, postSave: false); if (async) { @@ -946,7 +964,7 @@ await ExecuteWithStrategyInTransactionAsync( context.SaveChanges(); } - ValidateFixup(context, leftEntities, rightEntities); + ValidateFixup(context, leftEntities, rightEntities, postSave: true); keys = leftEntities.Select(e => e.Key2).ToList(); }, @@ -962,10 +980,10 @@ await ExecuteWithStrategyInTransactionAsync( var rightEntities = context.ChangeTracker.Entries() .Select(e => e.Entity).OrderBy(e => e.Name).ToList(); - ValidateFixup(context, leftEntities, rightEntities); + ValidateFixup(context, leftEntities, rightEntities, postSave: true); }); - static void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) + void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities, bool postSave) { var entries = context.ChangeTracker.Entries(); Assert.Equal(11, entries.Count()); @@ -981,7 +999,8 @@ static void ValidateFixup(DbContext context, IList leftEntit Assert.Single(rightEntities[1].CompositeKeySkipFull); Assert.Single(rightEntities[2].CompositeKeySkipFull); - foreach (var joinEntity in context.ChangeTracker.Entries().Select(e => e.Entity).ToList()) + var joinEntities = context.ChangeTracker.Entries().Select(e => e.Entity).ToList(); + foreach (var joinEntity in joinEntities) { Assert.Equal(joinEntity.Composite.Key1, joinEntity.CompositeId1); Assert.Equal(joinEntity.Composite.Key2, joinEntity.CompositeId2); @@ -991,6 +1010,16 @@ static void ValidateFixup(DbContext context, IList leftEntit Assert.Contains(joinEntity, joinEntity.Composite.JoinThreeFull); Assert.Contains(joinEntity, joinEntity.Three.JoinCompositeKeyFull); } + + // Issue #23814 + //VerifyRelationshipSnapshots(context, joinEntities); + //VerifyRelationshipSnapshots(context, leftEntities); + //VerifyRelationshipSnapshots(context, rightEntities); + + foreach (var entry in context.ChangeTracker.Entries()) + { + Assert.Equal(postSave ? EntityState.Unchanged : EntityState.Added, entry.State); + } } } @@ -1137,7 +1166,8 @@ void ValidateFixup( Assert.DoesNotContain(rightEntities[2].CompositeKeySkipFull, e => e.Key2 == "6_1"); Assert.Contains(rightEntities[2].CompositeKeySkipFull, e => e.Key2 == "Z7714"); - foreach (var joinEntry in context.ChangeTracker.Entries().ToList()) + var joinEntries = context.ChangeTracker.Entries().ToList(); + foreach (var joinEntry in joinEntries) { var joinEntity = joinEntry.Entity; @@ -1153,6 +1183,11 @@ void ValidateFixup( var allLeft = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Key2).ToList(); var allRight = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); + // Issue #23814 + // VerifyRelationshipSnapshots(context, joinEntries.Select(e => e.Entity)); + // VerifyRelationshipSnapshots(context, allLeft); + // VerifyRelationshipSnapshots(context, allRight); + var count = 0; foreach (var left in allLeft) { @@ -1411,7 +1446,7 @@ await ExecuteWithStrategyInTransactionAsync( ValidateFixup(context, leftEntities, rightEntities); }); - static void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) + void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) { Assert.Equal(11, context.ChangeTracker.Entries().Count()); Assert.Equal(6, context.ChangeTracker.Entries().Count()); @@ -1424,6 +1459,9 @@ static void ValidateFixup(DbContext context, IList leftEntities, ILis Assert.Equal(3, rightEntities[0].SelfSkipSharedRight.Count); Assert.Single(rightEntities[1].SelfSkipSharedRight); Assert.Single(rightEntities[2].SelfSkipSharedRight); + + VerifyRelationshipSnapshots(context, leftEntities); + VerifyRelationshipSnapshots(context, rightEntities); } } @@ -1561,6 +1599,9 @@ void ValidateFixup( var allLeft = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); var allRight = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); + VerifyRelationshipSnapshots(context, allLeft); + VerifyRelationshipSnapshots(context, allRight); + var joins = 0; foreach (var left in allLeft) { @@ -1658,7 +1699,7 @@ await ExecuteWithStrategyInTransactionAsync( ValidateFixup(context, leftEntities, rightEntities); }); - static void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) + void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) { Assert.Equal(11, context.ChangeTracker.Entries().Count()); Assert.Equal(3, context.ChangeTracker.Entries().Count()); @@ -1673,13 +1714,19 @@ static void ValidateFixup(DbContext context, IList leftEntities, ILis Assert.Single(rightEntities[1].TwoSkipFull); Assert.Single(rightEntities[2].TwoSkipFull); - foreach (var joinEntity in context.ChangeTracker.Entries().Select(e => e.Entity).ToList()) + var joinEntities = context.ChangeTracker.Entries().Select(e => e.Entity).ToList(); + foreach (var joinEntity in joinEntities) { Assert.Equal(joinEntity.Two.Id, joinEntity.TwoId); Assert.Equal(joinEntity.Three.Id, joinEntity.ThreeId); Assert.Contains(joinEntity, joinEntity.Two.JoinThreeFull); Assert.Contains(joinEntity, joinEntity.Three.JoinTwoFull); } + + VerifyRelationshipSnapshots(context, joinEntities); + VerifyRelationshipSnapshots(context, leftEntities); + VerifyRelationshipSnapshots(context, rightEntities); + } } @@ -1776,7 +1823,7 @@ public virtual void Can_update_many_to_many_with_navs() ValidateFixup(context, leftEntities, rightEntities, 24, 24, 60 - 4); }); - static void ValidateFixup( + void ValidateFixup( DbContext context, List leftEntities, List rightEntities, @@ -1806,7 +1853,8 @@ static void ValidateFixup( Assert.DoesNotContain(rightEntities[2].TwoSkipFull, e => e.Name == "EntityTwo 3"); Assert.Contains(rightEntities[2].TwoSkipFull, e => e.Name == "Z7714"); - foreach (var joinEntry in context.ChangeTracker.Entries().ToList()) + var joinEntries = context.ChangeTracker.Entries().ToList(); + foreach (var joinEntry in joinEntries) { var joinEntity = joinEntry.Entity; Assert.Equal(joinEntity.Two.Id, joinEntity.TwoId); @@ -1818,6 +1866,10 @@ static void ValidateFixup( var allLeft = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); var allRight = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); + VerifyRelationshipSnapshots(context, joinEntries.Select(e => e.Entity)); + VerifyRelationshipSnapshots(context, allLeft); + VerifyRelationshipSnapshots(context, allRight); + var count = 0; foreach (var left in allLeft) { @@ -1915,7 +1967,7 @@ await ExecuteWithStrategyInTransactionAsync( ValidateFixup(context, leftEntities, rightEntities); }); - static void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) + void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) { Assert.Equal(11, context.ChangeTracker.Entries().Count()); Assert.Equal(3, context.ChangeTracker.Entries().Count()); @@ -1929,6 +1981,9 @@ static void ValidateFixup(DbContext context, IList leftEntities, ILis Assert.Equal(3, rightEntities[0].OneSkip.Count); Assert.Single(rightEntities[1].OneSkip); Assert.Single(rightEntities[2].OneSkip); + + VerifyRelationshipSnapshots(context, leftEntities); + VerifyRelationshipSnapshots(context, rightEntities); } } @@ -2025,7 +2080,7 @@ public virtual void Can_update_many_to_many_with_inheritance() ValidateFixup(context, leftEntities, rightEntities, 24, 14, 55 - 4); }); - static void ValidateFixup( + void ValidateFixup( DbContext context, List leftEntities, List rightEntities, @@ -2058,6 +2113,9 @@ static void ValidateFixup( var allLeft = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); var allRight = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); + VerifyRelationshipSnapshots(context, allLeft); + VerifyRelationshipSnapshots(context, allRight); + var count = 0; foreach (var left in allLeft) { @@ -2183,7 +2241,8 @@ void ValidateFixup(DbContext context, IList leftEntities, IList().Select(e => e.Entity).ToList()) + var joinEntities = context.ChangeTracker.Entries().Select(e => e.Entity).ToList(); + foreach (var joinEntity in joinEntities) { Assert.Equal(joinEntity.Left.Id, joinEntity.LeftId); Assert.Equal(joinEntity.Right.Id, joinEntity.RightId); @@ -2200,6 +2259,10 @@ void ValidateFixup(DbContext context, IList leftEntities, IList e.Name == "EntityOne 6"); Assert.Contains(rightEntities[4].SelfSkipPayloadLeft, e => context.Entry(e).Property(e => e.Id).CurrentValue == keys[7]); - foreach (var joinEntry in context.ChangeTracker.Entries().ToList()) + var joinEntries = context.ChangeTracker.Entries().ToList(); + foreach (var joinEntry in joinEntries) { var joinEntity = joinEntry.Entity; Assert.Equal(joinEntity.Left.Id, joinEntity.LeftId); @@ -2372,6 +2436,10 @@ void ValidateFixup( var allLeft = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); var allRight = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); + VerifyRelationshipSnapshots(context, joinEntries.Select(e => e.Entity)); + VerifyRelationshipSnapshots(context, allLeft); + VerifyRelationshipSnapshots(context, allRight); + var joins = 0; foreach (var left in allLeft) { @@ -2484,6 +2552,9 @@ void ValidateFixup(DbContext context, IList leftEntities, IList context.Entry(context.EntityThrees.Local.Single(e => e.Name == name)).Property(e => e.Id).CurrentValue; - static void ValidateFixup( + void ValidateFixup( ManyToManyContext context, List leftEntities, List rightEntities, @@ -2643,7 +2714,8 @@ static void ValidateFixup( var oneId2 = GetEntityOneId(context, "EntityOne 20"); var threeId2 = GetEntityThreeId(context, "EntityThree 20"); - foreach (var joinEntry in context.ChangeTracker.Entries>().ToList()) + var joinEntries = context.ChangeTracker.Entries>().ToList(); + foreach (var joinEntry in joinEntries) { var joinEntity = joinEntry.Entity; @@ -2665,6 +2737,10 @@ static void ValidateFixup( var allLeft = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); var allRight = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); + VerifyRelationshipSnapshots(context, joinEntries.Select(e => e.Entity)); + VerifyRelationshipSnapshots(context, allLeft); + VerifyRelationshipSnapshots(context, allRight); + var count = 0; foreach (var left in allLeft) { @@ -2762,7 +2838,7 @@ await ExecuteWithStrategyInTransactionAsync( ValidateFixup(context, leftEntities, rightEntities); }); - static void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) + void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) { Assert.Equal(11, context.ChangeTracker.Entries().Count()); Assert.Equal(3, context.ChangeTracker.Entries().Count()); @@ -2776,6 +2852,9 @@ static void ValidateFixup(DbContext context, IList leftEntities, ILis Assert.Equal(3, rightEntities[0].OneSkipShared.Count); Assert.Single(rightEntities[1].OneSkipShared); Assert.Single(rightEntities[2].OneSkipShared); + + VerifyRelationshipSnapshots(context, leftEntities); + VerifyRelationshipSnapshots(context, rightEntities); } } @@ -2880,7 +2959,7 @@ public virtual void Can_update_many_to_many_shared() ValidateFixup(context, leftEntities, rightEntities, 24, 24, 49); }); - static void ValidateFixup( + void ValidateFixup( DbContext context, List leftEntities, List rightEntities, @@ -2913,6 +2992,9 @@ static void ValidateFixup( var allLeft = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); var allRight = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); + VerifyRelationshipSnapshots(context, allLeft); + VerifyRelationshipSnapshots(context, allRight); + var count = 0; foreach (var left in allLeft) { @@ -3025,7 +3107,8 @@ void ValidateFixup(DbContext context, IList leftEntities, IList().Select(e => e.Entity).ToList()) + var joinEntities = context.ChangeTracker.Entries().Select(e => e.Entity).ToList(); + foreach (var joinEntity in joinEntities) { Assert.Equal(joinEntity.One.Id, joinEntity.OneId); Assert.Equal(joinEntity.Three.Id, joinEntity.ThreeId); @@ -3037,6 +3120,10 @@ void ValidateFixup(DbContext context, IList leftEntities, IList context.Entry(context.EntityThrees.Local.Single(e => e.Name == name)).Property(e => e.Id).CurrentValue; - static void ValidateFixup( + void ValidateFixup( ManyToManyContext context, List leftEntities, List rightEntities, @@ -3190,7 +3277,8 @@ static void ValidateFixup( var oneId2 = GetEntityOneId(context, "EntityOne 20"); var threeId2 = GetEntityThreeId(context, "EntityThree 20"); - foreach (var joinEntry in context.ChangeTracker.Entries().ToList()) + var joinEntries = context.ChangeTracker.Entries().ToList(); + foreach (var joinEntry in joinEntries) { var joinEntity = joinEntry.Entity; Assert.Equal(joinEntity.One.Id, joinEntity.OneId); @@ -3216,6 +3304,10 @@ static void ValidateFixup( var allLeft = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); var allRight = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); + VerifyRelationshipSnapshots(context, joinEntries.Select(e => e.Entity)); + VerifyRelationshipSnapshots(context, allLeft); + VerifyRelationshipSnapshots(context, allRight); + var count = 0; foreach (var left in allLeft) { @@ -3438,7 +3530,7 @@ await ExecuteWithStrategyInTransactionAsync( ValidateFixup(context, leftEntities, rightEntities); }); - static void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) + void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) { Assert.Equal(11, context.ChangeTracker.Entries().Count()); Assert.Equal(3, context.ChangeTracker.Entries().Count()); @@ -3452,6 +3544,9 @@ static void ValidateFixup(DbContext context, IList leftEntities, ILis Assert.Equal(3, rightEntities[0].OneSkip.Count); Assert.Single(rightEntities[1].OneSkip); Assert.Single(rightEntities[2].OneSkip); + + VerifyRelationshipSnapshots(context, leftEntities); + VerifyRelationshipSnapshots(context, rightEntities); } } @@ -3598,6 +3693,9 @@ void ValidateFixup( var allLeft = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); var allRight = context.ChangeTracker.Entries().Select(e => e.Entity).OrderBy(e => e.Name).ToList(); + VerifyRelationshipSnapshots(context, allLeft); + VerifyRelationshipSnapshots(context, allRight); + var count = 0; foreach (var left in allLeft) { @@ -3796,7 +3894,7 @@ await ExecuteWithStrategyInTransactionAsync( Assert.Single(rightEntities[2].As); }); - static void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) + void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) { Assert.Equal(11, context.ChangeTracker.Entries().Count()); Assert.Equal(3, context.ChangeTracker.Entries().Count()); @@ -3810,6 +3908,9 @@ static void ValidateFixup(DbContext context, IList leftEnti Assert.Equal(3, rightEntities[0].As.Count); Assert.Single(rightEntities[1].As); Assert.Single(rightEntities[2].As); + + VerifyRelationshipSnapshots(context, leftEntities); + VerifyRelationshipSnapshots(context, rightEntities); } } @@ -3891,7 +3992,7 @@ await ExecuteWithStrategyInTransactionAsync( Assert.Single(rightEntities[2].Lefts); }); - static void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) + void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) { Assert.Equal(11, context.ChangeTracker.Entries().Count()); Assert.Equal(3, context.ChangeTracker.Entries().Count()); @@ -3905,6 +4006,9 @@ static void ValidateFixup(DbContext context, IList leftEntiti Assert.Equal(3, rightEntities[0].Lefts.Count); Assert.Single(rightEntities[1].Lefts); Assert.Single(rightEntities[2].Lefts); + + VerifyRelationshipSnapshots(context, leftEntities); + VerifyRelationshipSnapshots(context, rightEntities); } } @@ -4043,7 +4147,7 @@ await ExecuteWithStrategyInTransactionAsync( Assert.Single(rightEntities[2].Lefts); }); - static void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) + void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) { Assert.Equal(11, context.ChangeTracker.Entries().Count()); Assert.Equal(3, context.ChangeTracker.Entries().Count()); @@ -4057,6 +4161,9 @@ static void ValidateFixup(DbContext context, IList leftEntiti Assert.Equal(3, rightEntities[0].Lefts.Count); Assert.Single(rightEntities[1].Lefts); Assert.Single(rightEntities[2].Lefts); + + VerifyRelationshipSnapshots(context, leftEntities); + VerifyRelationshipSnapshots(context, rightEntities); } } @@ -4125,7 +4232,7 @@ await ExecuteWithStrategyInTransactionAsync( ValidateFixup(context, leftEntities, rightEntities); }); - static void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) + void ValidateFixup(DbContext context, IList leftEntities, IList rightEntities) { Assert.Equal(9, context.ChangeTracker.Entries().Count()); Assert.Equal(3, context.ChangeTracker.Entries().Count()); @@ -4139,6 +4246,9 @@ static void ValidateFixup(DbContext context, IList leftEnti Assert.Single(rightEntities[0].As); Assert.Single(rightEntities[1].As); Assert.Single(rightEntities[2].As); + + VerifyRelationshipSnapshots(context, leftEntities); + VerifyRelationshipSnapshots(context, rightEntities); } } @@ -4441,6 +4551,76 @@ static void ValidateFixup(DbContext context, IList leftEntities, ILis } } + protected void VerifyRelationshipSnapshots(DbContext context, IEnumerable entities) + { + try + { + context.ChangeTracker.AutoDetectChangesEnabled = false; + + foreach (var entity in entities) + { + var entityEntry = context.Entry(entity).GetInfrastructure(); + var entityType = entityEntry.EntityType; + + if (entityEntry.HasRelationshipSnapshot) + { + foreach (var property in entityType.GetForeignKeys().SelectMany(e => e.Properties)) + { + if (property.GetRelationshipIndex() >= 0) + { + Assert.Equal(entityEntry.GetRelationshipSnapshotValue(property), entityEntry[property]); + } + } + + foreach (var navigation in entityType.GetNavigations() + .Concat((IEnumerable)entityType.GetSkipNavigations())) + { + if (navigation.GetRelationshipIndex() >= 0) + { + var snapshot = entityEntry.GetRelationshipSnapshotValue(navigation); + var current = entityEntry[navigation]; + + if (navigation.IsCollection) + { + var currentCollection = ((IEnumerable)current)?.ToList(); + var snapshotCollection = ((IEnumerable)snapshot)?.ToList(); + + if (snapshot == null) + { + Assert.True(current == null || !currentCollection.Any()); + } + else if (current == null) + { + Assert.True(snapshot == null || !snapshotCollection.Any()); + } + else + { + Assert.Equal(snapshotCollection.Count, currentCollection.Count); + + foreach (var related in snapshotCollection) + { + Assert.Contains(currentCollection, c => ReferenceEquals(c, related)); + } + } + } + else + { + Assert.Same(snapshot, current); + } + } + } + } + } + } + finally + { + if (RequiresDetectChanges) + { + context.ChangeTracker.AutoDetectChangesEnabled = true; + } + } + } + private ICollection CreateCollection() => RequiresDetectChanges ? (ICollection)new List() : new ObservableCollection();