Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SaveChanges improperly throws an exception due to "circular dependency" #5305

Closed
danBhentschel opened this issue May 9, 2016 · 1 comment

Comments

@danBhentschel
Copy link

I have created an extremely simple unit test project that illustrates this problem:

https://github.com/danBhentschel/EF7CircularDependencyTest

It was created using code-first and a SQLite DB.

The short description is that I get an exception when attempting to SaveChanges():

Test method EFTest.TestParentChildRelationship.AllAtOnce threw exception:
System.InvalidOperationException: A circular dependency was detected: 'Child' {'ParentParentId'} -> 'Parent' {'ParentId'}, 'Parent' {'FavoriteChildChildId'} -> 'Child' {'ChildId'}.
at Microsoft.Data.Entity.Internal.Multigraph2.BatchingTopologicalSort(Func2 formatCycle)
at Microsoft.Data.Entity.Update.Internal.CommandBatchPreparer.d__5.MoveNext()
at Microsoft.Data.Entity.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
at Microsoft.Data.Entity.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.Data.Entity.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
at EFTest.TestParentChildRelationship.AllAtOnce() in C:\Users\DHentschel\Documents\Visual Studio 2015\Projects\EFTest\EFTest\TestParentChildRelationship.cs:line 37

However, if I try to save the exact same data to the DB, but break the commit step into two staggered calls to SaveChanges(), then the data can be successfully saved, indicating that there isn't actually a circular dependency in either the schema or the data.

  • danBhentschel
@rowanmiller
Copy link
Contributor

Hey,

In your model you have two one-to-many relationships that go in opposite directions. A child belongs to a parent, and a parent has a favorite child. So there is a Parent.FavoriteChildId foreign key and a Child.ParentId foreign key.

    class Parent
    {
        public int ParentId { get; set; }
        public string Name { get; set; }
        public List<Child> Children { get; set; }
        public Child FavoriteChild { get; set; }
    }

    class Child
    {
        public int ChildId { get; set; }
        public string Name { get; set; }
    }

So when you try to save, mark needs to be inserted first so that his key value can be referenced from the ParentId foreign key of the children. But the cyclic data arises because sally needs to be inserted before mark so that her key value can be referenced from the FavouriteChildId foreign key on mark.

            var mark = _context.Add(new Parent { Name = "Mark" });
            var tom = _context.Add(new Child { Name = "Tom" });
            var sally = _context.Add(new Child { Name = "Sally" });
            mark.Entity.Children = new List<Child> { tom.Entity, sally.Entity };
            mark.Entity.FavoriteChild = sally.Entity;
            _context.SaveChanges();

Breaking up into two separate save operations is the correct way to handle this.

~Rowan

@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants