From 5a02b329634f3ebb1b29a25f7879f3dd71e34722 Mon Sep 17 00:00:00 2001 From: Arthur Vickers Date: Sun, 11 Feb 2018 11:10:24 -0800 Subject: [PATCH] Update DeleteBehavior.Restrict to not apply when navigations are changed Issue #9703 Restrict now means that EF will never either set an FK to null or perform a cascade delete if an entity is deleted. This is the same as before, although the exception type may change--it's a negative case and we triaged this break as okay. However, if a navigation property is explicitly changed, then the FK associated with that navigation property will still be set to null. This is the change from the previous behavior. This changes some negative cases into positive cases, which was also triaged as okay. --- .../GraphUpdatesTestBase.cs | 1020 +++++++++-------- .../Internal/InternalEntityEntry.cs | 8 +- .../Internal/NavigationFixer.cs | 30 +- .../ChangeTracking/Internal/StateManager.cs | 2 +- .../GraphUpdatesInMemoryTest.cs | 60 +- .../GraphUpdatesSqlServerTest.cs | 379 ++++++ 6 files changed, 958 insertions(+), 541 deletions(-) diff --git a/src/EFCore.Specification.Tests/GraphUpdatesTestBase.cs b/src/EFCore.Specification.Tests/GraphUpdatesTestBase.cs index eb5de26cf11..0e8720efaa4 100644 --- a/src/EFCore.Specification.Tests/GraphUpdatesTestBase.cs +++ b/src/EFCore.Specification.Tests/GraphUpdatesTestBase.cs @@ -24,8 +24,10 @@ public abstract partial class GraphUpdatesTestBase : IClassFixture { @@ -33,13 +35,17 @@ public virtual void Optional_One_to_one_relationships_are_one_to_one() root.OptionalSingle = new OptionalSingle1(); - Assert.Throws(() => context.SaveChanges()); + updateException = Assert.Throws(() => context.SaveChanges()); }); + + return updateException; } [ConditionalFact] - public virtual void Required_One_to_one_relationships_are_one_to_one() + public virtual DbUpdateException Required_One_to_one_relationships_are_one_to_one() { + DbUpdateException updateException = null; + ExecuteWithStrategyInTransaction( context => { @@ -47,13 +53,17 @@ public virtual void Required_One_to_one_relationships_are_one_to_one() root.RequiredSingle = new RequiredSingle1(); - Assert.Throws(() => context.SaveChanges()); + updateException = Assert.Throws(() => context.SaveChanges()); }); + + return updateException; } [ConditionalFact] - public virtual void Optional_One_to_one_with_AK_relationships_are_one_to_one() + public virtual DbUpdateException Optional_One_to_one_with_AK_relationships_are_one_to_one() { + DbUpdateException updateException = null; + ExecuteWithStrategyInTransaction( context => { @@ -61,13 +71,17 @@ public virtual void Optional_One_to_one_with_AK_relationships_are_one_to_one() root.OptionalSingleAk = new OptionalSingleAk1(); - Assert.Throws(() => context.SaveChanges()); + updateException = Assert.Throws(() => context.SaveChanges()); }); + + return updateException; } [ConditionalFact] - public virtual void Required_One_to_one_with_AK_relationships_are_one_to_one() + public virtual DbUpdateException Required_One_to_one_with_AK_relationships_are_one_to_one() { + DbUpdateException updateException = null; + ExecuteWithStrategyInTransaction( context => { @@ -75,8 +89,10 @@ public virtual void Required_One_to_one_with_AK_relationships_are_one_to_one() root.RequiredSingleAk = new RequiredSingleAk1(); - Assert.Throws(() => context.SaveChanges()); + updateException = Assert.Throws(() => context.SaveChanges()); }); + + return updateException; } [Fact] @@ -409,32 +425,21 @@ public virtual void Save_removed_optional_many_to_one_dependents(ChangeMechanism Assert.True(context.ChangeTracker.HasChanges()); - if (Fixture.ForceRestrict - && (changeMechanism & ChangeMechanism.Fk) == 0) - { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(Optional1), nameof(Optional2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); - } - else - { - context.SaveChanges(); + context.SaveChanges(); - Assert.False(context.ChangeTracker.HasChanges()); + Assert.False(context.ChangeTracker.HasChanges()); - Assert.DoesNotContain(removed1, root.OptionalChildren); - Assert.DoesNotContain(removed2, childCollection); + Assert.DoesNotContain(removed1, root.OptionalChildren); + Assert.DoesNotContain(removed2, childCollection); - Assert.Null(removed1.Parent); - Assert.Null(removed2.Parent); - Assert.Null(removed1.ParentId); - Assert.Null(removed2.ParentId); - } + Assert.Null(removed1.Parent); + Assert.Null(removed2.Parent); + Assert.Null(removed1.ParentId); + Assert.Null(removed2.ParentId); }, context => { - if (!Fixture.ForceRestrict - && (changeMechanism & ChangeMechanism.Fk) == 0) + if ((changeMechanism & ChangeMechanism.Fk) == 0) { var loadedRoot = LoadOptionalGraph(context); @@ -614,78 +619,66 @@ public virtual void Save_changed_optional_one_to_one(ChangeMechanism changeMecha Assert.True(context.ChangeTracker.HasChanges()); - if (Fixture.ForceRestrict) - { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(Root), nameof(OptionalSingle1), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); - } - else - { - context.SaveChanges(); - - Assert.False(context.ChangeTracker.HasChanges()); + context.SaveChanges(); - Assert.Equal(root.Id, new1.RootId); - Assert.Equal(root.Id, new1d.DerivedRootId); - Assert.Equal(root.Id, new1dd.MoreDerivedRootId); - Assert.Equal(new1.Id, new2.BackId); - Assert.Equal(new1d.Id, new2d.BackId); - Assert.Equal(new1dd.Id, new2dd.BackId); - Assert.Same(root, new1.Root); - Assert.Same(root, new1d.DerivedRoot); - Assert.Same(root, new1dd.MoreDerivedRoot); - Assert.Same(new1, new2.Back); - Assert.Same(new1d, new2d.Back); - Assert.Same(new1dd, new2dd.Back); + Assert.False(context.ChangeTracker.HasChanges()); - Assert.Null(old1.Root); - Assert.Null(old1d.DerivedRoot); - Assert.Null(old1dd.MoreDerivedRoot); - Assert.Equal(old1, old2.Back); - Assert.Equal(old1d, old2d.Back); - Assert.Equal(old1dd, old2dd.Back); - Assert.Null(old1.RootId); - Assert.Null(old1d.DerivedRootId); - Assert.Null(old1dd.MoreDerivedRootId); - Assert.Equal(old1.Id, old2.BackId); - Assert.Equal(old1d.Id, old2d.BackId); - Assert.Equal(old1dd.Id, old2dd.BackId); + Assert.Equal(root.Id, new1.RootId); + Assert.Equal(root.Id, new1d.DerivedRootId); + Assert.Equal(root.Id, new1dd.MoreDerivedRootId); + Assert.Equal(new1.Id, new2.BackId); + Assert.Equal(new1d.Id, new2d.BackId); + Assert.Equal(new1dd.Id, new2dd.BackId); + Assert.Same(root, new1.Root); + Assert.Same(root, new1d.DerivedRoot); + Assert.Same(root, new1dd.MoreDerivedRoot); + Assert.Same(new1, new2.Back); + Assert.Same(new1d, new2d.Back); + Assert.Same(new1dd, new2dd.Back); + + Assert.Null(old1.Root); + Assert.Null(old1d.DerivedRoot); + Assert.Null(old1dd.MoreDerivedRoot); + Assert.Equal(old1, old2.Back); + Assert.Equal(old1d, old2d.Back); + Assert.Equal(old1dd, old2dd.Back); + Assert.Null(old1.RootId); + Assert.Null(old1d.DerivedRootId); + Assert.Null(old1dd.MoreDerivedRootId); + Assert.Equal(old1.Id, old2.BackId); + Assert.Equal(old1d.Id, old2d.BackId); + Assert.Equal(old1dd.Id, old2dd.BackId); - entries = context.ChangeTracker.Entries().ToList(); - } + entries = context.ChangeTracker.Entries().ToList(); }, context => { - if (!Fixture.ForceRestrict) - { - var loadedRoot = LoadOptionalGraph(context); + var loadedRoot = LoadOptionalGraph(context); - AssertKeys(root, loadedRoot); - AssertNavigations(loadedRoot); + AssertKeys(root, loadedRoot); + AssertNavigations(loadedRoot); - var loaded1 = context.Set().Single(e => e.Id == old1.Id); - var loaded1d = context.Set().Single(e => e.Id == old1d.Id); - var loaded1dd = context.Set().Single(e => e.Id == old1dd.Id); - var loaded2 = context.Set().Single(e => e.Id == old2.Id); - var loaded2d = context.Set().Single(e => e.Id == old2d.Id); - var loaded2dd = context.Set().Single(e => e.Id == old2dd.Id); + var loaded1 = context.Set().Single(e => e.Id == old1.Id); + var loaded1d = context.Set().Single(e => e.Id == old1d.Id); + var loaded1dd = context.Set().Single(e => e.Id == old1dd.Id); + var loaded2 = context.Set().Single(e => e.Id == old2.Id); + var loaded2d = context.Set().Single(e => e.Id == old2d.Id); + var loaded2dd = context.Set().Single(e => e.Id == old2dd.Id); - AssertEntries(entries, context.ChangeTracker.Entries().ToList()); + AssertEntries(entries, context.ChangeTracker.Entries().ToList()); - Assert.Null(loaded1.Root); - Assert.Null(loaded1d.Root); - Assert.Null(loaded1dd.Root); - Assert.Same(loaded1, loaded2.Back); - Assert.Same(loaded1d, loaded2d.Back); - Assert.Same(loaded1dd, loaded2dd.Back); - Assert.Null(loaded1.RootId); - Assert.Null(loaded1d.RootId); - Assert.Null(loaded1dd.RootId); - Assert.Equal(loaded1.Id, loaded2.BackId); - Assert.Equal(loaded1d.Id, loaded2d.BackId); - Assert.Equal(loaded1dd.Id, loaded2dd.BackId); - } + Assert.Null(loaded1.Root); + Assert.Null(loaded1d.Root); + Assert.Null(loaded1dd.Root); + Assert.Same(loaded1, loaded2.Back); + Assert.Same(loaded1d, loaded2d.Back); + Assert.Same(loaded1dd, loaded2dd.Back); + Assert.Null(loaded1.RootId); + Assert.Null(loaded1d.RootId); + Assert.Null(loaded1dd.RootId); + Assert.Equal(loaded1.Id, loaded2.BackId); + Assert.Equal(loaded1d.Id, loaded2d.BackId); + Assert.Equal(loaded1dd.Id, loaded2dd.BackId); }); } @@ -697,8 +690,10 @@ public virtual void Save_changed_optional_one_to_one(ChangeMechanism changeMecha [InlineData((int)(ChangeMechanism.Principal | ChangeMechanism.Fk))] [InlineData((int)(ChangeMechanism.Fk | ChangeMechanism.Dependent))] [InlineData((int)(ChangeMechanism.Principal | ChangeMechanism.Dependent | ChangeMechanism.Fk))] - public virtual void Save_required_one_to_one_changed_by_reference(ChangeMechanism changeMechanism) + public virtual DbUpdateException Save_required_one_to_one_changed_by_reference(ChangeMechanism changeMechanism) { + DbUpdateException updateException = null; + // This test is a bit strange because the relationships are PK<->PK, which means // that an existing entity has to be deleted and then a new entity created that has // the same key as the existing entry. In other words it is a new incarnation of the same @@ -730,9 +725,7 @@ public virtual void Save_required_one_to_one_changed_by_reference(ChangeMechanis if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredSingle1), nameof(RequiredSingle2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -791,6 +784,8 @@ public virtual void Save_required_one_to_one_changed_by_reference(ChangeMechanis AssertNavigations(loadedRoot); } }); + + return updateException; } [ConditionalTheory] @@ -991,29 +986,18 @@ public virtual void Sever_optional_one_to_one(ChangeMechanism changeMechanism) Assert.False(context.Entry(old1).Reference(e => e.Root).IsLoaded); Assert.True(context.ChangeTracker.HasChanges()); - if (Fixture.ForceRestrict - && (changeMechanism & ChangeMechanism.Fk) == 0) - { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(Root), nameof(OptionalSingle1), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); - } - else - { - context.SaveChanges(); + context.SaveChanges(); - Assert.False(context.ChangeTracker.HasChanges()); + Assert.False(context.ChangeTracker.HasChanges()); - Assert.Null(old1.Root); - Assert.Same(old1, old2.Back); - Assert.Null(old1.RootId); - Assert.Equal(old1.Id, old2.BackId); - } + Assert.Null(old1.Root); + Assert.Same(old1, old2.Back); + Assert.Null(old1.RootId); + Assert.Equal(old1.Id, old2.BackId); }, context => { - if (!Fixture.ForceRestrict - && (changeMechanism & ChangeMechanism.Fk) == 0) + if ((changeMechanism & ChangeMechanism.Fk) == 0) { var loadedRoot = LoadOptionalGraph(context); @@ -1035,8 +1019,10 @@ public virtual void Sever_optional_one_to_one(ChangeMechanism changeMechanism) [InlineData((int)ChangeMechanism.Dependent)] [InlineData((int)ChangeMechanism.Principal)] [InlineData((int)(ChangeMechanism.Principal | ChangeMechanism.Dependent))] - public virtual void Sever_required_one_to_one(ChangeMechanism changeMechanism) + public virtual DbUpdateException Sever_required_one_to_one(ChangeMechanism changeMechanism) { + DbUpdateException updateException = null; + Root root = null; RequiredSingle1 old1 = null; RequiredSingle2 old2 = null; @@ -1069,9 +1055,7 @@ public virtual void Sever_required_one_to_one(ChangeMechanism changeMechanism) if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredSingle1), nameof(RequiredSingle2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -1097,6 +1081,8 @@ public virtual void Sever_required_one_to_one(ChangeMechanism changeMechanism) Assert.False(context.Set().Any(e => e.Id == old2.Id)); } }); + + return updateException; } [ConditionalTheory] @@ -1480,40 +1466,29 @@ public virtual void Reparent_to_different_one_to_many(ChangeMechanism changeMech Assert.True(context.ChangeTracker.HasChanges()); - if (Fixture.ForceRestrict - && (changeMechanism & ChangeMechanism.Fk) == 0) - { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(OptionalAk1), nameof(OptionalComposite2), "{Id: 3}"), - Assert.Throws(() => context.SaveChanges()).Message); - } - else - { - context.SaveChanges(); + context.SaveChanges(); - Assert.False(context.ChangeTracker.HasChanges()); + Assert.False(context.ChangeTracker.HasChanges()); - Assert.Same(oldComposite2, oldParent.CompositeChildren.Single()); - Assert.Same(oldParent, oldComposite2.Parent); - Assert.Equal(oldParent.Id, oldComposite2.ParentId); - Assert.Null(oldComposite2.Parent2); - Assert.Null(oldComposite2.Parent2Id); + Assert.Same(oldComposite2, oldParent.CompositeChildren.Single()); + Assert.Same(oldParent, oldComposite2.Parent); + Assert.Equal(oldParent.Id, oldComposite2.ParentId); + Assert.Null(oldComposite2.Parent2); + Assert.Null(oldComposite2.Parent2Id); - Assert.Same(oldComposite1, newParent.CompositeChildren.Single()); - Assert.Same(newParent, oldComposite1.Parent2); - Assert.Equal(newParent.Id, oldComposite1.Parent2Id); - Assert.Null(oldComposite1.Parent); - Assert.Null(oldComposite1.ParentId); + Assert.Same(oldComposite1, newParent.CompositeChildren.Single()); + Assert.Same(newParent, oldComposite1.Parent2); + Assert.Equal(newParent.Id, oldComposite1.Parent2Id); + Assert.Null(oldComposite1.Parent); + Assert.Null(oldComposite1.ParentId); - entries = context.ChangeTracker.Entries().ToList(); + entries = context.ChangeTracker.Entries().ToList(); - Assert.Equal(compositeCount, context.Set().Count()); - } + Assert.Equal(compositeCount, context.Set().Count()); }, context => { - if (!Fixture.ForceRestrict - && (changeMechanism & ChangeMechanism.Fk) == 0) + if ((changeMechanism & ChangeMechanism.Fk) == 0) { var loadedRoot = LoadOptionalOneToManyGraph(context); @@ -2035,37 +2010,25 @@ public virtual void Save_removed_optional_many_to_one_dependents_with_alternate_ Assert.True(context.ChangeTracker.HasChanges()); - if (Fixture.ForceRestrict - && (changeMechanism & ChangeMechanism.Fk) == 0) - { - Add(root.OptionalChildrenAk, removed1); - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(OptionalAk1), nameof(OptionalAk2), "{Id: 4}"), - Assert.Throws(() => context.SaveChanges()).Message); - } - else - { - context.SaveChanges(); + context.SaveChanges(); - Assert.False(context.ChangeTracker.HasChanges()); + Assert.False(context.ChangeTracker.HasChanges()); - Assert.DoesNotContain(removed1, root.OptionalChildrenAk); - Assert.DoesNotContain(removed2, childCollection); - Assert.DoesNotContain(removed2c, childCompositeCollection); + Assert.DoesNotContain(removed1, root.OptionalChildrenAk); + Assert.DoesNotContain(removed2, childCollection); + Assert.DoesNotContain(removed2c, childCompositeCollection); - Assert.Null(removed1.Parent); - Assert.Null(removed2.Parent); - Assert.Null(removed2c.Parent); + Assert.Null(removed1.Parent); + Assert.Null(removed2.Parent); + Assert.Null(removed2c.Parent); - Assert.Null(removed1.ParentId); - Assert.Null(removed2.ParentId); - Assert.Null(removed2c.ParentId); - } + Assert.Null(removed1.ParentId); + Assert.Null(removed2.ParentId); + Assert.Null(removed2c.ParentId); }, context => { - if (!Fixture.ForceRestrict - && (changeMechanism & ChangeMechanism.Fk) == 0) + if ((changeMechanism & ChangeMechanism.Fk) == 0) { var loadedRoot = LoadOptionalAkGraph(context); @@ -2257,88 +2220,76 @@ public virtual void Save_changed_optional_one_to_one_with_alternate_key(ChangeMe Assert.True(context.ChangeTracker.HasChanges()); - if (Fixture.ForceRestrict) - { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(Root), nameof(OptionalSingleAk1), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); - } - else - { - context.SaveChanges(); - - Assert.False(context.ChangeTracker.HasChanges()); + context.SaveChanges(); - Assert.Equal(root.AlternateId, new1.RootId); - Assert.Equal(root.AlternateId, new1d.DerivedRootId); - Assert.Equal(root.AlternateId, new1dd.MoreDerivedRootId); - Assert.Equal(new1.AlternateId, new2.BackId); - Assert.Equal(new1.Id, new2c.BackId); - Assert.Equal(new1.AlternateId, new2c.ParentAlternateId); - Assert.Equal(new1d.AlternateId, new2d.BackId); - Assert.Equal(new1dd.AlternateId, new2dd.BackId); - Assert.Same(root, new1.Root); - Assert.Same(root, new1d.DerivedRoot); - Assert.Same(root, new1dd.MoreDerivedRoot); - Assert.Same(new1, new2.Back); - Assert.Same(new1, new2c.Back); - Assert.Same(new1d, new2d.Back); - Assert.Same(new1dd, new2dd.Back); + Assert.False(context.ChangeTracker.HasChanges()); - Assert.Null(old1.Root); - Assert.Null(old1d.DerivedRoot); - Assert.Null(old1dd.MoreDerivedRoot); - Assert.Same(old1, old2.Back); - Assert.Same(old1, old2c.Back); - Assert.Equal(old1d, old2d.Back); - Assert.Equal(old1dd, old2dd.Back); - Assert.Null(old1.RootId); - Assert.Null(old1d.DerivedRootId); - Assert.Null(old1dd.MoreDerivedRootId); - Assert.Equal(old1.AlternateId, old2.BackId); - Assert.Equal(old1.Id, old2c.BackId); - Assert.Equal(old1.AlternateId, old2c.ParentAlternateId); - Assert.Equal(old1d.AlternateId, old2d.BackId); - Assert.Equal(old1dd.AlternateId, old2dd.BackId); + Assert.Equal(root.AlternateId, new1.RootId); + Assert.Equal(root.AlternateId, new1d.DerivedRootId); + Assert.Equal(root.AlternateId, new1dd.MoreDerivedRootId); + Assert.Equal(new1.AlternateId, new2.BackId); + Assert.Equal(new1.Id, new2c.BackId); + Assert.Equal(new1.AlternateId, new2c.ParentAlternateId); + Assert.Equal(new1d.AlternateId, new2d.BackId); + Assert.Equal(new1dd.AlternateId, new2dd.BackId); + Assert.Same(root, new1.Root); + Assert.Same(root, new1d.DerivedRoot); + Assert.Same(root, new1dd.MoreDerivedRoot); + Assert.Same(new1, new2.Back); + Assert.Same(new1, new2c.Back); + Assert.Same(new1d, new2d.Back); + Assert.Same(new1dd, new2dd.Back); + + Assert.Null(old1.Root); + Assert.Null(old1d.DerivedRoot); + Assert.Null(old1dd.MoreDerivedRoot); + Assert.Same(old1, old2.Back); + Assert.Same(old1, old2c.Back); + Assert.Equal(old1d, old2d.Back); + Assert.Equal(old1dd, old2dd.Back); + Assert.Null(old1.RootId); + Assert.Null(old1d.DerivedRootId); + Assert.Null(old1dd.MoreDerivedRootId); + Assert.Equal(old1.AlternateId, old2.BackId); + Assert.Equal(old1.Id, old2c.BackId); + Assert.Equal(old1.AlternateId, old2c.ParentAlternateId); + Assert.Equal(old1d.AlternateId, old2d.BackId); + Assert.Equal(old1dd.AlternateId, old2dd.BackId); - entries = context.ChangeTracker.Entries().ToList(); - } + entries = context.ChangeTracker.Entries().ToList(); }, context => { - if (!Fixture.ForceRestrict) - { - var loadedRoot = LoadOptionalAkGraph(context); + var loadedRoot = LoadOptionalAkGraph(context); - AssertKeys(root, loadedRoot); - AssertNavigations(loadedRoot); + AssertKeys(root, loadedRoot); + AssertNavigations(loadedRoot); - var loaded1 = context.Set().Single(e => e.Id == old1.Id); - var loaded1d = context.Set().Single(e => e.Id == old1d.Id); - var loaded1dd = context.Set().Single(e => e.Id == old1dd.Id); - var loaded2 = context.Set().Single(e => e.Id == old2.Id); - var loaded2d = context.Set().Single(e => e.Id == old2d.Id); - var loaded2dd = context.Set().Single(e => e.Id == old2dd.Id); - var loaded2c = context.Set().Single(e => e.Id == old2c.Id); + var loaded1 = context.Set().Single(e => e.Id == old1.Id); + var loaded1d = context.Set().Single(e => e.Id == old1d.Id); + var loaded1dd = context.Set().Single(e => e.Id == old1dd.Id); + var loaded2 = context.Set().Single(e => e.Id == old2.Id); + var loaded2d = context.Set().Single(e => e.Id == old2d.Id); + var loaded2dd = context.Set().Single(e => e.Id == old2dd.Id); + var loaded2c = context.Set().Single(e => e.Id == old2c.Id); - AssertEntries(entries, context.ChangeTracker.Entries().ToList()); + AssertEntries(entries, context.ChangeTracker.Entries().ToList()); - Assert.Null(loaded1.Root); - Assert.Null(loaded1d.Root); - Assert.Null(loaded1dd.Root); - Assert.Same(loaded1, loaded2.Back); - Assert.Same(loaded1, loaded2c.Back); - Assert.Same(loaded1d, loaded2d.Back); - Assert.Same(loaded1dd, loaded2dd.Back); - Assert.Null(loaded1.RootId); - Assert.Null(loaded1d.RootId); - Assert.Null(loaded1dd.RootId); - Assert.Equal(loaded1.AlternateId, loaded2.BackId); - Assert.Equal(loaded1.Id, loaded2c.BackId); - Assert.Equal(loaded1.AlternateId, loaded2c.ParentAlternateId); - Assert.Equal(loaded1d.AlternateId, loaded2d.BackId); - Assert.Equal(loaded1dd.AlternateId, loaded2dd.BackId); - } + Assert.Null(loaded1.Root); + Assert.Null(loaded1d.Root); + Assert.Null(loaded1dd.Root); + Assert.Same(loaded1, loaded2.Back); + Assert.Same(loaded1, loaded2c.Back); + Assert.Same(loaded1d, loaded2d.Back); + Assert.Same(loaded1dd, loaded2dd.Back); + Assert.Null(loaded1.RootId); + Assert.Null(loaded1d.RootId); + Assert.Null(loaded1dd.RootId); + Assert.Equal(loaded1.AlternateId, loaded2.BackId); + Assert.Equal(loaded1.Id, loaded2c.BackId); + Assert.Equal(loaded1.AlternateId, loaded2c.ParentAlternateId); + Assert.Equal(loaded1d.AlternateId, loaded2d.BackId); + Assert.Equal(loaded1dd.AlternateId, loaded2dd.BackId); }); } @@ -2385,132 +2336,117 @@ public virtual void Save_changed_optional_one_to_one_with_alternate_key_in_store root2.OptionalSingleAkDerived = new1d; root2.OptionalSingleAkMoreDerived = new1dd; - if (Fixture.ForceRestrict) - { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(Root), nameof(OptionalSingleAk1), "{Id: 1}"), - Assert.Throws(() => context2.SaveChanges()).Message); - } - else - { - context2.SaveChanges(); - } - } - - if (!Fixture.ForceRestrict) - { - new1 = context.Set().Single(e => e.Id == new1.Id); - new1d = (OptionalSingleAk1Derived)context.Set().Single(e => e.Id == new1d.Id); - new1dd = (OptionalSingleAk1MoreDerived)context.Set().Single(e => e.Id == new1dd.Id); - new2 = context.Set().Single(e => e.Id == new2.Id); - new2c = context.Set().Single(e => e.Id == new2c.Id); - new2d = (OptionalSingleAk2Derived)context.Set().Single(e => e.Id == new2d.Id); - new2dd = (OptionalSingleAk2MoreDerived)context.Set().Single(e => e.Id == new2dd.Id); - - Assert.Equal(root.AlternateId, new1.RootId); - Assert.Equal(root.AlternateId, new1d.DerivedRootId); - Assert.Equal(root.AlternateId, new1dd.MoreDerivedRootId); - Assert.Equal(new1.AlternateId, new2.BackId); - Assert.Equal(new1.Id, new2c.BackId); - Assert.Equal(new1.AlternateId, new2c.ParentAlternateId); - Assert.Equal(new1d.AlternateId, new2d.BackId); - Assert.Equal(new1dd.AlternateId, new2dd.BackId); - Assert.Same(root, new1.Root); - Assert.Same(root, new1d.DerivedRoot); - Assert.Same(root, new1dd.MoreDerivedRoot); - Assert.Same(new1, new2.Back); - Assert.Same(new1, new2c.Back); - Assert.Same(new1d, new2d.Back); - Assert.Same(new1dd, new2dd.Back); - - Assert.Null(old1.Root); - Assert.Null(old1d.DerivedRoot); - Assert.Null(old1dd.MoreDerivedRoot); - Assert.Same(old1, old2.Back); - Assert.Same(old1, old2c.Back); - Assert.Equal(old1d, old2d.Back); - Assert.Equal(old1dd, old2dd.Back); - Assert.Null(old1.RootId); - Assert.Null(old1d.DerivedRootId); - Assert.Null(old1dd.MoreDerivedRootId); - Assert.Equal(old1.AlternateId, old2.BackId); - Assert.Equal(old1.Id, old2c.BackId); - Assert.Equal(old1.AlternateId, old2c.ParentAlternateId); - Assert.Equal(old1d.AlternateId, old2d.BackId); - Assert.Equal(old1dd.AlternateId, old2dd.BackId); - - context.SaveChanges(); + context2.SaveChanges(); + } + + new1 = context.Set().Single(e => e.Id == new1.Id); + new1d = (OptionalSingleAk1Derived)context.Set().Single(e => e.Id == new1d.Id); + new1dd = (OptionalSingleAk1MoreDerived)context.Set().Single(e => e.Id == new1dd.Id); + new2 = context.Set().Single(e => e.Id == new2.Id); + new2c = context.Set().Single(e => e.Id == new2c.Id); + new2d = (OptionalSingleAk2Derived)context.Set().Single(e => e.Id == new2d.Id); + new2dd = (OptionalSingleAk2MoreDerived)context.Set().Single(e => e.Id == new2dd.Id); + + Assert.Equal(root.AlternateId, new1.RootId); + Assert.Equal(root.AlternateId, new1d.DerivedRootId); + Assert.Equal(root.AlternateId, new1dd.MoreDerivedRootId); + Assert.Equal(new1.AlternateId, new2.BackId); + Assert.Equal(new1.Id, new2c.BackId); + Assert.Equal(new1.AlternateId, new2c.ParentAlternateId); + Assert.Equal(new1d.AlternateId, new2d.BackId); + Assert.Equal(new1dd.AlternateId, new2dd.BackId); + Assert.Same(root, new1.Root); + Assert.Same(root, new1d.DerivedRoot); + Assert.Same(root, new1dd.MoreDerivedRoot); + Assert.Same(new1, new2.Back); + Assert.Same(new1, new2c.Back); + Assert.Same(new1d, new2d.Back); + Assert.Same(new1dd, new2dd.Back); + + Assert.Null(old1.Root); + Assert.Null(old1d.DerivedRoot); + Assert.Null(old1dd.MoreDerivedRoot); + Assert.Same(old1, old2.Back); + Assert.Same(old1, old2c.Back); + Assert.Equal(old1d, old2d.Back); + Assert.Equal(old1dd, old2dd.Back); + Assert.Null(old1.RootId); + Assert.Null(old1d.DerivedRootId); + Assert.Null(old1dd.MoreDerivedRootId); + Assert.Equal(old1.AlternateId, old2.BackId); + Assert.Equal(old1.Id, old2c.BackId); + Assert.Equal(old1.AlternateId, old2c.ParentAlternateId); + Assert.Equal(old1d.AlternateId, old2d.BackId); + Assert.Equal(old1dd.AlternateId, old2dd.BackId); - Assert.Equal(root.AlternateId, new1.RootId); - Assert.Equal(root.AlternateId, new1d.DerivedRootId); - Assert.Equal(root.AlternateId, new1dd.MoreDerivedRootId); - Assert.Equal(new1.AlternateId, new2.BackId); - Assert.Equal(new1.Id, new2c.BackId); - Assert.Equal(new1.AlternateId, new2c.ParentAlternateId); - Assert.Equal(new1d.AlternateId, new2d.BackId); - Assert.Equal(new1dd.AlternateId, new2dd.BackId); - Assert.Same(root, new1.Root); - Assert.Same(root, new1d.DerivedRoot); - Assert.Same(root, new1dd.MoreDerivedRoot); - Assert.Same(new1, new2.Back); - Assert.Same(new1, new2c.Back); - Assert.Same(new1d, new2d.Back); - Assert.Same(new1dd, new2dd.Back); + context.SaveChanges(); - Assert.Null(old1.Root); - Assert.Null(old1d.DerivedRoot); - Assert.Null(old1dd.MoreDerivedRoot); - Assert.Same(old1, old2.Back); - Assert.Same(old1, old2c.Back); - Assert.Equal(old1d, old2d.Back); - Assert.Equal(old1dd, old2dd.Back); - Assert.Null(old1.RootId); - Assert.Null(old1d.DerivedRootId); - Assert.Null(old1dd.MoreDerivedRootId); - Assert.Equal(old1.AlternateId, old2.BackId); - Assert.Equal(old1.Id, old2c.BackId); - Assert.Equal(old1.AlternateId, old2c.ParentAlternateId); - Assert.Equal(old1d.AlternateId, old2d.BackId); - Assert.Equal(old1dd.AlternateId, old2dd.BackId); + Assert.Equal(root.AlternateId, new1.RootId); + Assert.Equal(root.AlternateId, new1d.DerivedRootId); + Assert.Equal(root.AlternateId, new1dd.MoreDerivedRootId); + Assert.Equal(new1.AlternateId, new2.BackId); + Assert.Equal(new1.Id, new2c.BackId); + Assert.Equal(new1.AlternateId, new2c.ParentAlternateId); + Assert.Equal(new1d.AlternateId, new2d.BackId); + Assert.Equal(new1dd.AlternateId, new2dd.BackId); + Assert.Same(root, new1.Root); + Assert.Same(root, new1d.DerivedRoot); + Assert.Same(root, new1dd.MoreDerivedRoot); + Assert.Same(new1, new2.Back); + Assert.Same(new1, new2c.Back); + Assert.Same(new1d, new2d.Back); + Assert.Same(new1dd, new2dd.Back); + + Assert.Null(old1.Root); + Assert.Null(old1d.DerivedRoot); + Assert.Null(old1dd.MoreDerivedRoot); + Assert.Same(old1, old2.Back); + Assert.Same(old1, old2c.Back); + Assert.Equal(old1d, old2d.Back); + Assert.Equal(old1dd, old2dd.Back); + Assert.Null(old1.RootId); + Assert.Null(old1d.DerivedRootId); + Assert.Null(old1dd.MoreDerivedRootId); + Assert.Equal(old1.AlternateId, old2.BackId); + Assert.Equal(old1.Id, old2c.BackId); + Assert.Equal(old1.AlternateId, old2c.ParentAlternateId); + Assert.Equal(old1d.AlternateId, old2d.BackId); + Assert.Equal(old1dd.AlternateId, old2dd.BackId); - entries = context.ChangeTracker.Entries().ToList(); - } + entries = context.ChangeTracker.Entries().ToList(); }, context => { - if (!Fixture.ForceRestrict) - { - var loadedRoot = LoadOptionalAkGraph(context); + var loadedRoot = LoadOptionalAkGraph(context); - AssertKeys(root, loadedRoot); - AssertNavigations(loadedRoot); + AssertKeys(root, loadedRoot); + AssertNavigations(loadedRoot); - var loaded1 = context.Set().Single(e => e.Id == old1.Id); - var loaded1d = context.Set().Single(e => e.Id == old1d.Id); - var loaded1dd = context.Set().Single(e => e.Id == old1dd.Id); - var loaded2 = context.Set().Single(e => e.Id == old2.Id); - var loaded2d = context.Set().Single(e => e.Id == old2d.Id); - var loaded2dd = context.Set().Single(e => e.Id == old2dd.Id); - var loaded2c = context.Set().Single(e => e.Id == old2c.Id); + var loaded1 = context.Set().Single(e => e.Id == old1.Id); + var loaded1d = context.Set().Single(e => e.Id == old1d.Id); + var loaded1dd = context.Set().Single(e => e.Id == old1dd.Id); + var loaded2 = context.Set().Single(e => e.Id == old2.Id); + var loaded2d = context.Set().Single(e => e.Id == old2d.Id); + var loaded2dd = context.Set().Single(e => e.Id == old2dd.Id); + var loaded2c = context.Set().Single(e => e.Id == old2c.Id); - AssertEntries(entries, context.ChangeTracker.Entries().ToList()); + AssertEntries(entries, context.ChangeTracker.Entries().ToList()); - Assert.Null(loaded1.Root); - Assert.Null(loaded1d.Root); - Assert.Null(loaded1dd.Root); - Assert.Same(loaded1, loaded2.Back); - Assert.Same(loaded1, loaded2c.Back); - Assert.Same(loaded1d, loaded2d.Back); - Assert.Same(loaded1dd, loaded2dd.Back); - Assert.Null(loaded1.RootId); - Assert.Null(loaded1d.RootId); - Assert.Null(loaded1dd.RootId); - Assert.Equal(loaded1.AlternateId, loaded2.BackId); - Assert.Equal(loaded1.Id, loaded2c.BackId); - Assert.Equal(loaded1.AlternateId, loaded2c.ParentAlternateId); - Assert.Equal(loaded1d.AlternateId, loaded2d.BackId); - Assert.Equal(loaded1dd.AlternateId, loaded2dd.BackId); - } + Assert.Null(loaded1.Root); + Assert.Null(loaded1d.Root); + Assert.Null(loaded1dd.Root); + Assert.Same(loaded1, loaded2.Back); + Assert.Same(loaded1, loaded2c.Back); + Assert.Same(loaded1d, loaded2d.Back); + Assert.Same(loaded1dd, loaded2dd.Back); + Assert.Null(loaded1.RootId); + Assert.Null(loaded1d.RootId); + Assert.Null(loaded1dd.RootId); + Assert.Equal(loaded1.AlternateId, loaded2.BackId); + Assert.Equal(loaded1.Id, loaded2c.BackId); + Assert.Equal(loaded1.AlternateId, loaded2c.ParentAlternateId); + Assert.Equal(loaded1d.AlternateId, loaded2d.BackId); + Assert.Equal(loaded1dd.AlternateId, loaded2dd.BackId); }); } @@ -2827,32 +2763,21 @@ public virtual void Sever_optional_one_to_one_with_alternate_key(ChangeMechanism Assert.False(context.Entry(old1).Reference(e => e.Root).IsLoaded); Assert.True(context.ChangeTracker.HasChanges()); - if (Fixture.ForceRestrict - && (changeMechanism & ChangeMechanism.Fk) == 0) - { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(Root), nameof(OptionalSingleAk1), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); - } - else - { - context.SaveChanges(); + context.SaveChanges(); - Assert.False(context.ChangeTracker.HasChanges()); + Assert.False(context.ChangeTracker.HasChanges()); - Assert.Null(old1.Root); - Assert.Same(old1, old2.Back); - Assert.Same(old1, old2c.Back); - Assert.Null(old1.RootId); - Assert.Equal(old1.AlternateId, old2.BackId); - Assert.Equal(old1.Id, old2c.BackId); - Assert.Equal(old1.AlternateId, old2c.ParentAlternateId); - } + Assert.Null(old1.Root); + Assert.Same(old1, old2.Back); + Assert.Same(old1, old2c.Back); + Assert.Null(old1.RootId); + Assert.Equal(old1.AlternateId, old2.BackId); + Assert.Equal(old1.Id, old2c.BackId); + Assert.Equal(old1.AlternateId, old2c.ParentAlternateId); }, context => { - if (!Fixture.ForceRestrict - && (changeMechanism & ChangeMechanism.Fk) == 0) + if ((changeMechanism & ChangeMechanism.Fk) == 0) { var loadedRoot = LoadOptionalAkGraph(context); @@ -3295,8 +3220,10 @@ public virtual void Reparent_required_non_PK_one_to_one_with_alternate_key(Chang } [ConditionalFact] - public virtual void Required_many_to_one_dependents_are_cascade_deleted() + public virtual DbUpdateException Required_many_to_one_dependents_are_cascade_deleted() { + DbUpdateException updateException = null; + var removedId = 0; List orphanedIds = null; @@ -3321,9 +3248,7 @@ public virtual void Required_many_to_one_dependents_are_cascade_deleted() if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(Required1), nameof(Required2), "{Id: 2}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -3357,11 +3282,15 @@ public virtual void Required_many_to_one_dependents_are_cascade_deleted() Assert.Empty(context.Set().Where(e => orphanedIds.Contains(e.Id))); } }); + + return updateException; } [ConditionalFact] - public virtual void Optional_many_to_one_dependents_are_orphaned() + public virtual DbUpdateException Optional_many_to_one_dependents_are_orphaned() { + DbUpdateException updateException = null; + var removedId = 0; List orphanedIds = null; @@ -3386,9 +3315,7 @@ public virtual void Optional_many_to_one_dependents_are_orphaned() if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(Optional1), nameof(Optional2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -3422,11 +3349,15 @@ public virtual void Optional_many_to_one_dependents_are_orphaned() Assert.Equal(orphanedIds.Count, context.Set().Count(e => orphanedIds.Contains(e.Id))); } }); + + return updateException; } [ConditionalFact] - public virtual void Optional_one_to_one_are_orphaned() + public virtual DbUpdateException Optional_one_to_one_are_orphaned() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; @@ -3447,9 +3378,7 @@ public virtual void Optional_one_to_one_are_orphaned() if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(OptionalSingle1), nameof(OptionalSingle2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -3481,11 +3410,15 @@ public virtual void Optional_one_to_one_are_orphaned() Assert.Equal(1, context.Set().Count(e => e.Id == orphanedId)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_one_to_one_are_cascade_deleted() + public virtual DbUpdateException Required_one_to_one_are_cascade_deleted() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; @@ -3506,9 +3439,7 @@ public virtual void Required_one_to_one_are_cascade_deleted() if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredSingle1), nameof(RequiredSingle2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -3540,11 +3471,15 @@ public virtual void Required_one_to_one_are_cascade_deleted() Assert.Empty(context.Set().Where(e => e.Id == orphanedId)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_non_PK_one_to_one_are_cascade_deleted() + public virtual DbUpdateException Required_non_PK_one_to_one_are_cascade_deleted() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; @@ -3565,9 +3500,7 @@ public virtual void Required_non_PK_one_to_one_are_cascade_deleted() if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredNonPkSingle1), nameof(RequiredNonPkSingle2), "{Id: 2}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -3599,11 +3532,15 @@ public virtual void Required_non_PK_one_to_one_are_cascade_deleted() Assert.Empty(context.Set().Where(e => e.Id == orphanedId)); } }); + + return updateException; } [ConditionalFact] - public virtual void Optional_many_to_one_dependents_with_alternate_key_are_orphaned() + public virtual DbUpdateException Optional_many_to_one_dependents_with_alternate_key_are_orphaned() { + DbUpdateException updateException = null; + var removedId = 0; List orphanedIds = null; @@ -3628,9 +3565,7 @@ public virtual void Optional_many_to_one_dependents_with_alternate_key_are_orpha if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(OptionalAk1), nameof(OptionalAk2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -3664,11 +3599,15 @@ public virtual void Optional_many_to_one_dependents_with_alternate_key_are_orpha Assert.Equal(orphanedIds.Count, context.Set().Count(e => orphanedIds.Contains(e.Id))); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_many_to_one_dependents_with_alternate_key_are_cascade_deleted() + public virtual DbUpdateException Required_many_to_one_dependents_with_alternate_key_are_cascade_deleted() { + DbUpdateException updateException = null; + var removedId = 0; List orphanedIds = null; List orphanedIdCs = null; @@ -3697,9 +3636,7 @@ public virtual void Required_many_to_one_dependents_with_alternate_key_are_casca if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredAk1), nameof(RequiredAk2), "{Id: 3}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -3735,11 +3672,15 @@ public virtual void Required_many_to_one_dependents_with_alternate_key_are_casca Assert.Empty(context.Set().Where(e => orphanedIdCs.Contains(e.Id))); } }); + + return updateException; } [ConditionalFact] - public virtual void Optional_one_to_one_with_alternate_key_are_orphaned() + public virtual DbUpdateException Optional_one_to_one_with_alternate_key_are_orphaned() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; var orphanedIdC = 0; @@ -3763,9 +3704,7 @@ public virtual void Optional_one_to_one_with_alternate_key_are_orphaned() if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(OptionalSingleAk1), nameof(OptionalSingleAk2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -3800,11 +3739,15 @@ public virtual void Optional_one_to_one_with_alternate_key_are_orphaned() Assert.Equal(1, context.Set().Count(e => e.Id == orphanedIdC)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_one_to_one_with_alternate_key_are_cascade_deleted() + public virtual DbUpdateException Required_one_to_one_with_alternate_key_are_cascade_deleted() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; var orphanedIdC = 0; @@ -3828,9 +3771,7 @@ public virtual void Required_one_to_one_with_alternate_key_are_cascade_deleted() if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredSingleAk1), nameof(RequiredSingleAk2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -3865,11 +3806,15 @@ public virtual void Required_one_to_one_with_alternate_key_are_cascade_deleted() Assert.Empty(context.Set().Where(e => e.Id == orphanedIdC)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_non_PK_one_to_one_with_alternate_key_are_cascade_deleted() + public virtual DbUpdateException Required_non_PK_one_to_one_with_alternate_key_are_cascade_deleted() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; @@ -3890,9 +3835,7 @@ public virtual void Required_non_PK_one_to_one_with_alternate_key_are_cascade_de if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredNonPkSingleAk1), nameof(RequiredNonPkSingleAk2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -3924,11 +3867,15 @@ public virtual void Required_non_PK_one_to_one_with_alternate_key_are_cascade_de Assert.Empty(context.Set().Where(e => e.Id == orphanedId)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_many_to_one_dependents_are_cascade_deleted_in_store() + public virtual DbUpdateException Required_many_to_one_dependents_are_cascade_deleted_in_store() { + DbUpdateException updateException = null; + var removedId = 0; List orphanedIds = null; @@ -3956,7 +3903,8 @@ public virtual void Required_many_to_one_dependents_are_cascade_deleted_in_store if (Fixture.ForceRestrict) { - Assert.Throws(() => context.SaveChanges()); + updateException = Assert.Throws(() => context.SaveChanges()); + } else { @@ -3989,11 +3937,15 @@ public virtual void Required_many_to_one_dependents_are_cascade_deleted_in_store Assert.Empty(context.Set().Where(e => orphanedIds.Contains(e.Id))); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_one_to_one_are_cascade_deleted_in_store() + public virtual DbUpdateException Required_one_to_one_are_cascade_deleted_in_store() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; @@ -4018,7 +3970,7 @@ public virtual void Required_one_to_one_are_cascade_deleted_in_store() if (Fixture.ForceRestrict) { - Assert.Throws(() => context.SaveChanges()); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4049,11 +4001,15 @@ public virtual void Required_one_to_one_are_cascade_deleted_in_store() Assert.Empty(context.Set().Where(e => e.Id == orphanedId)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_non_PK_one_to_one_are_cascade_deleted_in_store() + public virtual DbUpdateException Required_non_PK_one_to_one_are_cascade_deleted_in_store() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; @@ -4078,7 +4034,7 @@ public virtual void Required_non_PK_one_to_one_are_cascade_deleted_in_store() if (Fixture.ForceRestrict) { - Assert.Throws(() => context.SaveChanges()); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4109,11 +4065,15 @@ public virtual void Required_non_PK_one_to_one_are_cascade_deleted_in_store() Assert.Empty(context.Set().Where(e => e.Id == orphanedId)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_many_to_one_dependents_with_alternate_key_are_cascade_deleted_in_store() + public virtual DbUpdateException Required_many_to_one_dependents_with_alternate_key_are_cascade_deleted_in_store() { + DbUpdateException updateException = null; + var removedId = 0; List orphanedIds = null; List orphanedIdCs = null; @@ -4142,7 +4102,7 @@ public virtual void Required_many_to_one_dependents_with_alternate_key_are_casca if (Fixture.ForceRestrict) { - Assert.Throws(() => context.SaveChanges()); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4177,11 +4137,15 @@ public virtual void Required_many_to_one_dependents_with_alternate_key_are_casca Assert.Empty(context.Set().Where(e => orphanedIdCs.Contains(e.Id))); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_one_to_one_with_alternate_key_are_cascade_deleted_in_store() + public virtual DbUpdateException Required_one_to_one_with_alternate_key_are_cascade_deleted_in_store() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; var orphanedIdC = 0; @@ -4208,7 +4172,7 @@ public virtual void Required_one_to_one_with_alternate_key_are_cascade_deleted_i if (Fixture.ForceRestrict) { - Assert.Throws(() => context.SaveChanges()); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4241,11 +4205,15 @@ public virtual void Required_one_to_one_with_alternate_key_are_cascade_deleted_i Assert.Empty(context.Set().Where(e => e.Id == orphanedIdC)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_non_PK_one_to_one_with_alternate_key_are_cascade_deleted_in_store() + public virtual DbUpdateException Required_non_PK_one_to_one_with_alternate_key_are_cascade_deleted_in_store() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; @@ -4270,7 +4238,7 @@ public virtual void Required_non_PK_one_to_one_with_alternate_key_are_cascade_de if (Fixture.ForceRestrict) { - Assert.Throws(() => context.SaveChanges()); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4301,11 +4269,15 @@ public virtual void Required_non_PK_one_to_one_with_alternate_key_are_cascade_de Assert.Empty(context.Set().Where(e => e.Id == orphanedId)); } }); + + return updateException; } [ConditionalFact] - public virtual void Optional_many_to_one_dependents_are_orphaned_in_store() + public virtual DbUpdateException Optional_many_to_one_dependents_are_orphaned_in_store() { + DbUpdateException updateException = null; + var removedId = 0; List orphanedIds = null; @@ -4333,7 +4305,7 @@ public virtual void Optional_many_to_one_dependents_are_orphaned_in_store() if (Fixture.ForceRestrict) { - Assert.Throws(() => context.SaveChanges()); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4372,11 +4344,15 @@ public virtual void Optional_many_to_one_dependents_are_orphaned_in_store() Assert.True(orphaned.All(e => e.ParentId == null)); } }); + + return updateException; } [ConditionalFact] - public virtual void Optional_one_to_one_are_orphaned_in_store() + public virtual DbUpdateException Optional_one_to_one_are_orphaned_in_store() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; @@ -4401,7 +4377,7 @@ public virtual void Optional_one_to_one_are_orphaned_in_store() if (Fixture.ForceRestrict) { - Assert.Throws(() => context.SaveChanges()); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4432,11 +4408,15 @@ public virtual void Optional_one_to_one_are_orphaned_in_store() Assert.Null(context.Set().Single(e => e.Id == orphanedId).BackId); } }); + + return updateException; } [ConditionalFact] - public virtual void Optional_many_to_one_dependents_with_alternate_key_are_orphaned_in_store() + public virtual DbUpdateException Optional_many_to_one_dependents_with_alternate_key_are_orphaned_in_store() { + DbUpdateException updateException = null; + var removedId = 0; List orphanedIds = null; List orphanedIdCs = null; @@ -4470,9 +4450,7 @@ public virtual void Optional_many_to_one_dependents_with_alternate_key_are_orpha if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(OptionalAk1), nameof(OptionalComposite2), "{Id: 3}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4519,11 +4497,15 @@ public virtual void Optional_many_to_one_dependents_with_alternate_key_are_orpha Assert.True(orphanedC.All(e => e.ParentId == null)); } }); + + return updateException; } [ConditionalFact] - public virtual void Optional_one_to_one_with_alternate_key_are_orphaned_in_store() + public virtual DbUpdateException Optional_one_to_one_with_alternate_key_are_orphaned_in_store() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; var orphanedIdC = 0; @@ -4554,9 +4536,7 @@ public virtual void Optional_one_to_one_with_alternate_key_are_orphaned_in_store if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(OptionalSingleAk1), nameof(OptionalSingleComposite2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4589,11 +4569,15 @@ public virtual void Optional_one_to_one_with_alternate_key_are_orphaned_in_store Assert.Null(context.Set().Single(e => e.Id == orphanedIdC).BackId); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_many_to_one_dependents_are_cascade_deleted_starting_detached() + public virtual DbUpdateException Required_many_to_one_dependents_are_cascade_deleted_starting_detached() { + DbUpdateException updateException = null; + var removedId = 0; List orphanedIds = null; Root root = null; @@ -4624,9 +4608,7 @@ public virtual void Required_many_to_one_dependents_are_cascade_deleted_starting if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(Required1), nameof(Required2), "{Id: 2}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4654,11 +4636,15 @@ public virtual void Required_many_to_one_dependents_are_cascade_deleted_starting Assert.Empty(context.Set().Where(e => orphanedIds.Contains(e.Id))); } }); + + return updateException; } [ConditionalFact] - public virtual void Optional_many_to_one_dependents_are_orphaned_starting_detached() + public virtual DbUpdateException Optional_many_to_one_dependents_are_orphaned_starting_detached() { + DbUpdateException updateException = null; + var removedId = 0; List orphanedIds = null; Root root = null; @@ -4689,9 +4675,7 @@ public virtual void Optional_many_to_one_dependents_are_orphaned_starting_detach if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(Optional1), nameof(Optional2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4719,11 +4703,15 @@ public virtual void Optional_many_to_one_dependents_are_orphaned_starting_detach Assert.Equal(orphanedIds.Count, context.Set().Count(e => orphanedIds.Contains(e.Id))); } }); + + return updateException; } [ConditionalFact] - public virtual void Optional_one_to_one_are_orphaned_starting_detached() + public virtual DbUpdateException Optional_one_to_one_are_orphaned_starting_detached() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; Root root = null; @@ -4747,9 +4735,7 @@ public virtual void Optional_one_to_one_are_orphaned_starting_detached() if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(OptionalSingle1), nameof(OptionalSingle2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4776,11 +4762,15 @@ public virtual void Optional_one_to_one_are_orphaned_starting_detached() Assert.Equal(1, context.Set().Count(e => e.Id == orphanedId)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_one_to_one_are_cascade_deleted_starting_detached() + public virtual DbUpdateException Required_one_to_one_are_cascade_deleted_starting_detached() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; Root root = null; @@ -4804,9 +4794,7 @@ public virtual void Required_one_to_one_are_cascade_deleted_starting_detached() if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredSingle1), nameof(RequiredSingle2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4832,11 +4820,15 @@ public virtual void Required_one_to_one_are_cascade_deleted_starting_detached() Assert.Empty(context.Set().Where(e => e.Id == orphanedId)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_non_PK_one_to_one_are_cascade_deleted_starting_detached() + public virtual DbUpdateException Required_non_PK_one_to_one_are_cascade_deleted_starting_detached() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; Root root = null; @@ -4860,9 +4852,7 @@ public virtual void Required_non_PK_one_to_one_are_cascade_deleted_starting_deta if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredNonPkSingle1), nameof(RequiredNonPkSingle2), "{Id: 2}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4889,11 +4879,15 @@ public virtual void Required_non_PK_one_to_one_are_cascade_deleted_starting_deta Assert.Empty(context.Set().Where(e => e.Id == orphanedId)); } }); + + return updateException; } [ConditionalFact] - public virtual void Optional_many_to_one_dependents_with_alternate_key_are_orphaned_starting_detached() + public virtual DbUpdateException Optional_many_to_one_dependents_with_alternate_key_are_orphaned_starting_detached() { + DbUpdateException updateException = null; + var removedId = 0; List orphanedIds = null; List orphanedIdCs = null; @@ -4929,9 +4923,7 @@ public virtual void Optional_many_to_one_dependents_with_alternate_key_are_orpha if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(OptionalAk1), nameof(OptionalAk2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -4961,11 +4953,15 @@ public virtual void Optional_many_to_one_dependents_with_alternate_key_are_orpha Assert.Equal(orphanedIdCs.Count, context.Set().Count(e => orphanedIdCs.Contains(e.Id))); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_many_to_one_dependents_with_alternate_key_are_cascade_deleted_starting_detached() + public virtual DbUpdateException Required_many_to_one_dependents_with_alternate_key_are_cascade_deleted_starting_detached() { + DbUpdateException updateException = null; + var removedId = 0; List orphanedIds = null; List orphanedIdCs = null; @@ -5000,9 +4996,7 @@ public virtual void Required_many_to_one_dependents_with_alternate_key_are_casca if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredAk1), nameof(RequiredAk2), "{Id: 3}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -5032,11 +5026,15 @@ public virtual void Required_many_to_one_dependents_with_alternate_key_are_casca Assert.Empty(context.Set().Where(e => orphanedIdCs.Contains(e.Id))); } }); + + return updateException; } [ConditionalFact] - public virtual void Optional_one_to_one_with_alternate_key_are_orphaned_starting_detached() + public virtual DbUpdateException Optional_one_to_one_with_alternate_key_are_orphaned_starting_detached() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; var orphanedIdC = 0; @@ -5064,9 +5062,7 @@ public virtual void Optional_one_to_one_with_alternate_key_are_orphaned_starting if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(OptionalSingleAk1), nameof(OptionalSingleAk2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -5095,11 +5091,15 @@ public virtual void Optional_one_to_one_with_alternate_key_are_orphaned_starting Assert.Equal(1, context.Set().Count(e => e.Id == orphanedIdC)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_one_to_one_with_alternate_key_are_cascade_deleted_starting_detached() + public virtual DbUpdateException Required_one_to_one_with_alternate_key_are_cascade_deleted_starting_detached() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; var orphanedIdC = 0; @@ -5127,9 +5127,7 @@ public virtual void Required_one_to_one_with_alternate_key_are_cascade_deleted_s if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredSingleAk1), nameof(RequiredSingleAk2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -5158,11 +5156,15 @@ public virtual void Required_one_to_one_with_alternate_key_are_cascade_deleted_s Assert.Empty(context.Set().Where(e => e.Id == orphanedIdC)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_non_PK_one_to_one_with_alternate_key_are_cascade_deleted_starting_detached() + public virtual DbUpdateException Required_non_PK_one_to_one_with_alternate_key_are_cascade_deleted_starting_detached() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; Root root = null; @@ -5186,9 +5188,7 @@ public virtual void Required_non_PK_one_to_one_with_alternate_key_are_cascade_de if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredNonPkSingleAk1), nameof(RequiredNonPkSingleAk2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -5215,11 +5215,15 @@ public virtual void Required_non_PK_one_to_one_with_alternate_key_are_cascade_de Assert.Empty(context.Set().Where(e => e.Id == orphanedId)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_many_to_one_dependents_are_cascade_detached_when_Added() + public virtual DbUpdateException Required_many_to_one_dependents_are_cascade_detached_when_Added() { + DbUpdateException updateException = null; + var removedId = 0; List orphanedIds = null; @@ -5260,9 +5264,7 @@ public virtual void Required_many_to_one_dependents_are_cascade_detached_when_Ad if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(Required1), nameof(Required2), "{Id: 2}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -5291,11 +5293,15 @@ public virtual void Required_many_to_one_dependents_are_cascade_detached_when_Ad Assert.Empty(context.Set().Where(e => orphanedIds.Contains(e.Id))); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_one_to_one_are_cascade_detached_when_Added() + public virtual DbUpdateException Required_one_to_one_are_cascade_detached_when_Added() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; @@ -5324,9 +5330,7 @@ public virtual void Required_one_to_one_are_cascade_detached_when_Added() if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredSingle1), nameof(RequiredSingle2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -5353,11 +5357,15 @@ public virtual void Required_one_to_one_are_cascade_detached_when_Added() Assert.Empty(context.Set().Where(e => e.Id == orphanedId)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_non_PK_one_to_one_are_cascade_detached_when_Added() + public virtual DbUpdateException Required_non_PK_one_to_one_are_cascade_detached_when_Added() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; @@ -5386,9 +5394,7 @@ public virtual void Required_non_PK_one_to_one_are_cascade_detached_when_Added() if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredNonPkSingle1), nameof(RequiredNonPkSingle2), "{Id: 2}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -5415,11 +5421,15 @@ public virtual void Required_non_PK_one_to_one_are_cascade_detached_when_Added() Assert.Empty(context.Set().Where(e => e.Id == orphanedId)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_many_to_one_dependents_with_alternate_key_are_cascade_detached_when_Added() + public virtual DbUpdateException Required_many_to_one_dependents_with_alternate_key_are_cascade_detached_when_Added() { + DbUpdateException updateException = null; + var removedId = 0; List orphanedIds = null; List orphanedIdCs = null; @@ -5470,9 +5480,7 @@ public virtual void Required_many_to_one_dependents_with_alternate_key_are_casca if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredAk1), nameof(RequiredAk2), "{Id: 3}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -5504,11 +5512,15 @@ public virtual void Required_many_to_one_dependents_with_alternate_key_are_casca Assert.Empty(context.Set().Where(e => orphanedIdCs.Contains(e.Id))); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_one_to_one_with_alternate_key_are_cascade_detached_when_Added() + public virtual DbUpdateException Required_one_to_one_with_alternate_key_are_cascade_detached_when_Added() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; var orphanedIdC = 0; @@ -5543,9 +5555,7 @@ public virtual void Required_one_to_one_with_alternate_key_are_cascade_detached_ if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredSingleAk1), nameof(RequiredSingleAk2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -5574,11 +5584,15 @@ public virtual void Required_one_to_one_with_alternate_key_are_cascade_detached_ Assert.Empty(context.Set().Where(e => e.Id == orphanedIdC)); } }); + + return updateException; } [ConditionalFact] - public virtual void Required_non_PK_one_to_one_with_alternate_key_are_cascade_detached_when_Added() + public virtual DbUpdateException Required_non_PK_one_to_one_with_alternate_key_are_cascade_detached_when_Added() { + DbUpdateException updateException = null; + var removedId = 0; var orphanedId = 0; @@ -5607,9 +5621,7 @@ public virtual void Required_non_PK_one_to_one_with_alternate_key_are_cascade_de if (Fixture.ForceRestrict) { - Assert.Equal( - CoreStrings.RelationshipConceptualNullSensitive(nameof(RequiredNonPkSingleAk1), nameof(RequiredNonPkSingleAk2), "{Id: 1}"), - Assert.Throws(() => context.SaveChanges()).Message); + updateException = Assert.Throws(() => context.SaveChanges()); } else { @@ -5636,6 +5648,8 @@ public virtual void Required_non_PK_one_to_one_with_alternate_key_are_cascade_de Assert.Empty(context.Set().Where(e => e.Id == orphanedId)); } }); + + return updateException; } [ConditionalFact] diff --git a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs index 5bd4273435e..1a538042b0f 100644 --- a/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs +++ b/src/EFCore/ChangeTracking/Internal/InternalEntityEntry.cs @@ -318,7 +318,7 @@ public virtual void MarkUnchangedFromQuery([CanBeNull] ISet handled StateManager.InternalEntityEntryNotifier.StateChanged(this, EntityState.Detached, fromQuery: true); StateManager.OnTracked(this, fromQuery: true); - + var trackingQueryMode = StateManager.GetTrackingQueryMode(EntityType); if (trackingQueryMode != TrackingQueryMode.Simple) { @@ -809,8 +809,7 @@ public virtual void SetProperty([NotNull] IPropertyBase propertyBase, [CanBeNull if (asProperty != null && (!asProperty.ClrType.IsNullableType() || asProperty.GetContainingForeignKeys().Any( - fk => (fk.DeleteBehavior == DeleteBehavior.Cascade - || fk.DeleteBehavior == DeleteBehavior.Restrict) + fk => (fk.DeleteBehavior == DeleteBehavior.Cascade) && fk.DeclaringEntityType.IsAssignableFrom(EntityType)))) { if (value == null) @@ -954,8 +953,7 @@ public virtual void HandleConceptualNulls(bool sensitiveLoggingEnabled) if (_stateData.IsPropertyFlagged(property.GetIndex(), PropertyFlag.Null)) { if (properties.Any(p => p.IsNullable) - && foreignKey.DeleteBehavior != DeleteBehavior.Cascade - && foreignKey.DeleteBehavior != DeleteBehavior.Restrict) + && foreignKey.DeleteBehavior != DeleteBehavior.Cascade) { foreach (var toNull in properties) { diff --git a/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs b/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs index 9bba70e8db3..3c408e83225 100644 --- a/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs +++ b/src/EFCore/ChangeTracking/Internal/NavigationFixer.cs @@ -487,29 +487,35 @@ private void DeleteFixup(InternalEntityEntry entry) foreach (var foreignKey in entityType.GetForeignKeys()) { - var principalToDependent = foreignKey.PrincipalToDependent; - if (principalToDependent != null) + if (foreignKey.DeleteBehavior != DeleteBehavior.Restrict) { - var principalEntry = stateManager.GetPrincipal(entry, foreignKey); - if (principalEntry != null - && principalEntry.EntityState != EntityState.Deleted) + var principalToDependent = foreignKey.PrincipalToDependent; + if (principalToDependent != null) { - ResetReferenceOrRemoveCollection(principalEntry, principalToDependent, entry); + var principalEntry = stateManager.GetPrincipal(entry, foreignKey); + if (principalEntry != null + && principalEntry.EntityState != EntityState.Deleted) + { + ResetReferenceOrRemoveCollection(principalEntry, principalToDependent, entry); + } } } } foreach (var foreignKey in entityType.GetReferencingForeignKeys()) { - var dependentToPrincipal = foreignKey.DependentToPrincipal; - if (dependentToPrincipal != null) + if (foreignKey.DeleteBehavior != DeleteBehavior.Restrict) { - var dependentEntries = stateManager.GetDependents(entry, foreignKey); - foreach (var dependentEntry in dependentEntries) + var dependentToPrincipal = foreignKey.DependentToPrincipal; + if (dependentToPrincipal != null) { - if (dependentEntry[dependentToPrincipal] == entry.Entity) + var dependentEntries = stateManager.GetDependents(entry, foreignKey); + foreach (var dependentEntry in dependentEntries) { - SetNavigation(dependentEntry, dependentToPrincipal, null); + if (dependentEntry[dependentToPrincipal] == entry.Entity) + { + SetNavigation(dependentEntry, dependentToPrincipal, null); + } } } } diff --git a/src/EFCore/ChangeTracking/Internal/StateManager.cs b/src/EFCore/ChangeTracking/Internal/StateManager.cs index 5169b4c2fb9..7705a78d4b7 100644 --- a/src/EFCore/ChangeTracking/Internal/StateManager.cs +++ b/src/EFCore/ChangeTracking/Internal/StateManager.cs @@ -826,7 +826,7 @@ private void CascadeDelete(InternalEntityEntry entry) CascadeDelete(dependent); } - else + else if (fk.DeleteBehavior != DeleteBehavior.Restrict) { foreach (var dependentProperty in fk.Properties) { diff --git a/test/EFCore.InMemory.FunctionalTests/GraphUpdatesInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/GraphUpdatesInMemoryTest.cs index 14e5011c8fb..2987021d3e8 100644 --- a/test/EFCore.InMemory.FunctionalTests/GraphUpdatesInMemoryTest.cs +++ b/test/EFCore.InMemory.FunctionalTests/GraphUpdatesInMemoryTest.cs @@ -15,24 +15,28 @@ public GraphUpdatesInMemoryTest(GraphUpdatesInMemoryFixture fixture) { } - public override void Optional_One_to_one_relationships_are_one_to_one() + public override DbUpdateException Optional_One_to_one_relationships_are_one_to_one() { // FK uniqueness not enforced in in-memory database + return null; } - public override void Required_One_to_one_relationships_are_one_to_one() + public override DbUpdateException Required_One_to_one_relationships_are_one_to_one() { // FK uniqueness not enforced in in-memory database + return null; } - public override void Optional_One_to_one_with_AK_relationships_are_one_to_one() + public override DbUpdateException Optional_One_to_one_with_AK_relationships_are_one_to_one() { // FK uniqueness not enforced in in-memory database + return null; } - public override void Required_One_to_one_with_AK_relationships_are_one_to_one() + public override DbUpdateException Required_One_to_one_with_AK_relationships_are_one_to_one() { // FK uniqueness not enforced in in-memory database + return null; } public override void Save_required_one_to_one_changed_by_reference_with_alternate_key(ChangeMechanism changeMechanism, bool useExistingEntities) @@ -45,9 +49,10 @@ public override void Save_required_non_PK_one_to_one_changed_by_reference_with_a // Cascade delete not supported by in-memory database } - public override void Save_required_one_to_one_changed_by_reference(ChangeMechanism changeMechanism) + public override DbUpdateException Save_required_one_to_one_changed_by_reference(ChangeMechanism changeMechanism) { // Cascade delete not supported by in-memory database + return null; } public override void Save_removed_required_many_to_one_dependents(ChangeMechanism changeMechanism) @@ -65,9 +70,10 @@ public override void Sever_required_one_to_one_with_alternate_key(ChangeMechanis // Cascade delete not supported by in-memory database } - public override void Sever_required_one_to_one(ChangeMechanism changeMechanism) + public override DbUpdateException Sever_required_one_to_one(ChangeMechanism changeMechanism) { // Cascade delete not supported by in-memory database + return null; } public override void Sever_required_non_PK_one_to_one(ChangeMechanism changeMechanism) @@ -80,74 +86,88 @@ public override void Sever_required_non_PK_one_to_one_with_alternate_key(ChangeM // Cascade delete not supported by in-memory database } - public override void Required_many_to_one_dependents_are_cascade_deleted_in_store() + public override DbUpdateException Required_many_to_one_dependents_are_cascade_deleted_in_store() { // Cascade delete not supported by in-memory database + return null; } - public override void Required_one_to_one_are_cascade_deleted_in_store() + public override DbUpdateException Required_one_to_one_are_cascade_deleted_in_store() { // Cascade delete not supported by in-memory database + return null; } - public override void Required_non_PK_one_to_one_are_cascade_deleted_in_store() + public override DbUpdateException Required_non_PK_one_to_one_are_cascade_deleted_in_store() { // Cascade delete not supported by in-memory database + return null; } - public override void Required_many_to_one_dependents_with_alternate_key_are_cascade_deleted_in_store() + public override DbUpdateException Required_many_to_one_dependents_with_alternate_key_are_cascade_deleted_in_store() { // Cascade delete not supported by in-memory database + return null; } - public override void Required_one_to_one_with_alternate_key_are_cascade_deleted_in_store() + public override DbUpdateException Required_one_to_one_with_alternate_key_are_cascade_deleted_in_store() { // Cascade delete not supported by in-memory database + return null; } - public override void Required_non_PK_one_to_one_with_alternate_key_are_cascade_deleted_in_store() + public override DbUpdateException Required_non_PK_one_to_one_with_alternate_key_are_cascade_deleted_in_store() { // Cascade delete not supported by in-memory database + return null; } - public override void Optional_many_to_one_dependents_are_orphaned_in_store() + public override DbUpdateException Optional_many_to_one_dependents_are_orphaned_in_store() { // Cascade nulls not supported by in-memory database + return null; } - public override void Optional_one_to_one_are_orphaned_in_store() + public override DbUpdateException Optional_one_to_one_are_orphaned_in_store() { // Cascade nulls not supported by in-memory database + return null; } - public override void Optional_many_to_one_dependents_with_alternate_key_are_orphaned_in_store() + public override DbUpdateException Optional_many_to_one_dependents_with_alternate_key_are_orphaned_in_store() { // Cascade nulls not supported by in-memory database + return null; } - public override void Optional_one_to_one_with_alternate_key_are_orphaned_in_store() + public override DbUpdateException Optional_one_to_one_with_alternate_key_are_orphaned_in_store() { // Cascade nulls not supported by in-memory database + return null; } - public override void Required_non_PK_one_to_one_with_alternate_key_are_cascade_detached_when_Added() + public override DbUpdateException Required_non_PK_one_to_one_with_alternate_key_are_cascade_detached_when_Added() { // Cascade nulls not supported by in-memory database + return null; } - public override void Required_one_to_one_are_cascade_detached_when_Added() + public override DbUpdateException Required_one_to_one_are_cascade_detached_when_Added() { // Cascade nulls not supported by in-memory database + return null; } - public override void Required_one_to_one_with_alternate_key_are_cascade_detached_when_Added() + public override DbUpdateException Required_one_to_one_with_alternate_key_are_cascade_detached_when_Added() { // Cascade nulls not supported by in-memory database + return null; } - public override void Required_non_PK_one_to_one_are_cascade_detached_when_Added() + public override DbUpdateException Required_non_PK_one_to_one_are_cascade_detached_when_Added() { // Cascade nulls not supported by in-memory database + return null; } protected override void ExecuteWithStrategyInTransaction( diff --git a/test/EFCore.SqlServer.FunctionalTests/GraphUpdatesSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/GraphUpdatesSqlServerTest.cs index df5183fd6f9..b5047a07a0b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/GraphUpdatesSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/GraphUpdatesSqlServerTest.cs @@ -8,6 +8,7 @@ using Microsoft.EntityFrameworkCore.TestUtilities; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Xunit; namespace Microsoft.EntityFrameworkCore { @@ -58,6 +59,384 @@ public Restrict(GraphUpdatesWithRestrictSqlServerFixture fixture) { } + public override DbUpdateException Optional_One_to_one_relationships_are_one_to_one() + { + var updateException = base.Optional_One_to_one_relationships_are_one_to_one(); + + Assert.Contains("IX_OptionalSingle1_RootId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_One_to_one_relationships_are_one_to_one() + { + var updateException = base.Required_One_to_one_relationships_are_one_to_one(); + + Assert.Contains("PK_RequiredSingle1", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Optional_One_to_one_with_AK_relationships_are_one_to_one() + { + var updateException = base.Optional_One_to_one_with_AK_relationships_are_one_to_one(); + + Assert.Contains("IX_OptionalSingleAk1_RootId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_One_to_one_with_AK_relationships_are_one_to_one() + { + var updateException = base.Required_One_to_one_with_AK_relationships_are_one_to_one(); + + Assert.Contains("IX_RequiredSingleAk1_RootId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Save_required_one_to_one_changed_by_reference(ChangeMechanism changeMechanism) + { + var updateException = base.Save_required_one_to_one_changed_by_reference(changeMechanism); + + Assert.Contains("FK_RequiredSingle2_RequiredSingle1_Id", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Sever_required_one_to_one(ChangeMechanism changeMechanism) + { + var updateException = base.Sever_required_one_to_one(changeMechanism); + + Assert.Contains("FK_RequiredSingle2_RequiredSingle1_Id", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_many_to_one_dependents_are_cascade_deleted() + { + var updateException = base.Required_many_to_one_dependents_are_cascade_deleted(); + + Assert.Contains("FK_Required2_Required1_ParentId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Optional_many_to_one_dependents_are_orphaned() + { + var updateException = base.Optional_many_to_one_dependents_are_orphaned(); + + Assert.Contains("FK_Optional2_Optional1_ParentId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Optional_one_to_one_are_orphaned() + { + var updateException = base.Optional_one_to_one_are_orphaned(); + + Assert.Contains("FK_OptionalSingle2_OptionalSingle1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_one_to_one_are_cascade_deleted() + { + var updateException = base.Required_one_to_one_are_cascade_deleted(); + + Assert.Contains("FK_RequiredSingle2_RequiredSingle1_Id", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_non_PK_one_to_one_are_cascade_deleted() + { + var updateException = base.Required_non_PK_one_to_one_are_cascade_deleted(); + + Assert.Contains("FK_RequiredNonPkSingle2_RequiredNonPkSingle1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Optional_many_to_one_dependents_with_alternate_key_are_orphaned() + { + var updateException = base.Optional_many_to_one_dependents_with_alternate_key_are_orphaned(); + + Assert.Contains("FK_OptionalAk2_OptionalAk1_ParentId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_many_to_one_dependents_with_alternate_key_are_cascade_deleted() + { + var updateException = base.Required_many_to_one_dependents_with_alternate_key_are_cascade_deleted(); + + Assert.Contains("FK_RequiredAk2_RequiredAk1_ParentId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Optional_one_to_one_with_alternate_key_are_orphaned() + { + var updateException = base.Optional_one_to_one_with_alternate_key_are_orphaned(); + + Assert.Contains("FK_OptionalSingleAk2_OptionalSingleAk1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_one_to_one_with_alternate_key_are_cascade_deleted() + { + var updateException = base.Required_one_to_one_with_alternate_key_are_cascade_deleted(); + + Assert.Contains("FK_RequiredSingleAk2_RequiredSingleAk1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_non_PK_one_to_one_with_alternate_key_are_cascade_deleted() + { + var updateException = base.Required_non_PK_one_to_one_with_alternate_key_are_cascade_deleted(); + + Assert.Contains("FK_RequiredNonPkSingleAk2_RequiredNonPkSingleAk1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_many_to_one_dependents_are_cascade_deleted_in_store() + { + var updateException = base.Required_many_to_one_dependents_are_cascade_deleted_in_store(); + + Assert.Contains("FK_Required2_Required1_ParentId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_one_to_one_are_cascade_deleted_in_store() + { + var updateException = base.Required_one_to_one_are_cascade_deleted_in_store(); + + Assert.Contains("FK_RequiredSingle2_RequiredSingle1_Id", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_non_PK_one_to_one_are_cascade_deleted_in_store() + { + var updateException = base.Required_non_PK_one_to_one_are_cascade_deleted_in_store(); + + Assert.Contains("FK_RequiredNonPkSingle2_RequiredNonPkSingle1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_many_to_one_dependents_with_alternate_key_are_cascade_deleted_in_store() + { + var updateException = base.Required_many_to_one_dependents_with_alternate_key_are_cascade_deleted_in_store(); + + Assert.Contains("FK_RequiredAk2_RequiredAk1_ParentId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_one_to_one_with_alternate_key_are_cascade_deleted_in_store() + { + var updateException = base.Required_one_to_one_with_alternate_key_are_cascade_deleted_in_store(); + + Assert.Contains("FK_RequiredSingleAk2_RequiredSingleAk1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_non_PK_one_to_one_with_alternate_key_are_cascade_deleted_in_store() + { + var updateException = base.Required_non_PK_one_to_one_with_alternate_key_are_cascade_deleted_in_store(); + + Assert.Contains("FK_RequiredNonPkSingleAk2_RequiredNonPkSingleAk1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Optional_many_to_one_dependents_are_orphaned_in_store() + { + var updateException = base.Optional_many_to_one_dependents_are_orphaned_in_store(); + + Assert.Contains("FK_Optional2_Optional1_ParentId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Optional_one_to_one_are_orphaned_in_store() + { + var updateException = base.Optional_one_to_one_are_orphaned_in_store(); + + Assert.Contains("FK_OptionalSingle2_OptionalSingle1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Optional_many_to_one_dependents_with_alternate_key_are_orphaned_in_store() + { + var updateException = base.Optional_many_to_one_dependents_with_alternate_key_are_orphaned_in_store(); + + Assert.Contains("FK_OptionalAk2_OptionalAk1_ParentId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Optional_one_to_one_with_alternate_key_are_orphaned_in_store() + { + var updateException = base.Optional_one_to_one_with_alternate_key_are_orphaned_in_store(); + + Assert.Contains("FK_OptionalSingleAk2_OptionalSingleAk1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_many_to_one_dependents_are_cascade_deleted_starting_detached() + { + var updateException = base.Required_many_to_one_dependents_are_cascade_deleted_starting_detached(); + + Assert.Contains("FK_Required2_Required1_ParentId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Optional_many_to_one_dependents_are_orphaned_starting_detached() + { + var updateException = base.Optional_many_to_one_dependents_are_orphaned_starting_detached(); + + Assert.Contains("FK_Optional2_Optional1_ParentId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Optional_one_to_one_are_orphaned_starting_detached() + { + var updateException = base.Optional_one_to_one_are_orphaned_starting_detached(); + + Assert.Contains("FK_OptionalSingle2_OptionalSingle1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_one_to_one_are_cascade_deleted_starting_detached() + { + var updateException = base.Required_one_to_one_are_cascade_deleted_starting_detached(); + + Assert.Contains("FK_RequiredSingle2_RequiredSingle1_Id", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_non_PK_one_to_one_are_cascade_deleted_starting_detached() + { + var updateException = base.Required_non_PK_one_to_one_are_cascade_deleted_starting_detached(); + + Assert.Contains("FK_RequiredNonPkSingle2_RequiredNonPkSingle1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Optional_many_to_one_dependents_with_alternate_key_are_orphaned_starting_detached() + { + var updateException = base.Optional_many_to_one_dependents_with_alternate_key_are_orphaned_starting_detached(); + + Assert.Contains("FK_OptionalAk2_OptionalAk1_ParentId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_many_to_one_dependents_with_alternate_key_are_cascade_deleted_starting_detached() + { + var updateException = base.Required_many_to_one_dependents_with_alternate_key_are_cascade_deleted_starting_detached(); + + Assert.Contains("FK_RequiredAk2_RequiredAk1_ParentId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Optional_one_to_one_with_alternate_key_are_orphaned_starting_detached() + { + var updateException = base.Optional_one_to_one_with_alternate_key_are_orphaned_starting_detached(); + + Assert.Contains("FK_OptionalSingleAk2_OptionalSingleAk1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_one_to_one_with_alternate_key_are_cascade_deleted_starting_detached() + { + var updateException = base.Required_one_to_one_with_alternate_key_are_cascade_deleted_starting_detached(); + + Assert.Contains("FK_RequiredSingleAk2_RequiredSingleAk1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_non_PK_one_to_one_with_alternate_key_are_cascade_deleted_starting_detached() + { + var updateException = base.Required_non_PK_one_to_one_with_alternate_key_are_cascade_deleted_starting_detached(); + + Assert.Contains("FK_RequiredNonPkSingleAk2_RequiredNonPkSingleAk1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_many_to_one_dependents_are_cascade_detached_when_Added() + { + var updateException = base.Required_many_to_one_dependents_are_cascade_detached_when_Added(); + + Assert.Contains("FK_Required2_Required1_ParentId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_one_to_one_are_cascade_detached_when_Added() + { + var updateException = base.Required_one_to_one_are_cascade_detached_when_Added(); + + Assert.Contains("FK_RequiredSingle2_RequiredSingle1_Id", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_non_PK_one_to_one_are_cascade_detached_when_Added() + { + var updateException = base.Required_non_PK_one_to_one_are_cascade_detached_when_Added(); + + Assert.Contains("FK_RequiredNonPkSingle2_RequiredNonPkSingle1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_many_to_one_dependents_with_alternate_key_are_cascade_detached_when_Added() + { + var updateException = base.Required_many_to_one_dependents_with_alternate_key_are_cascade_detached_when_Added(); + + Assert.Contains("FK_RequiredAk2_RequiredAk1_ParentId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_one_to_one_with_alternate_key_are_cascade_detached_when_Added() + { + var updateException = base.Required_one_to_one_with_alternate_key_are_cascade_detached_when_Added(); + + Assert.Contains("FK_RequiredSingleAk2_RequiredSingleAk1_BackId", updateException.InnerException.Message); + + return updateException; + } + + public override DbUpdateException Required_non_PK_one_to_one_with_alternate_key_are_cascade_detached_when_Added() + { + var updateException = base.Required_non_PK_one_to_one_with_alternate_key_are_cascade_detached_when_Added(); + + Assert.Contains("FK_RequiredNonPkSingleAk2_RequiredNonPkSingleAk1_BackId", updateException.InnerException.Message); + + return updateException; + } + public class GraphUpdatesWithRestrictSqlServerFixture : GraphUpdatesSqlServerFixtureBase { protected override string StoreName { get; } = "GraphRestrictUpdatesTest";