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 circular dependency in unique unfiltered index (when change doesn't affect any column from unique index). #30601

Closed
jmalczak opened this issue Mar 31, 2023 · 0 comments
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported regression Servicing-approved type-bug
Milestone

Comments

@jmalczak
Copy link

jmalczak commented Mar 31, 2023

When using Attach and IsModified to update column without first fetching whole entity from database, SaveChanges throws circular dependency in unique unfiltered index, even if updated column is not part of the index. This code works fine in ef core 6.

Repro steps

 [Fact]
    public void SaveChangesShouldNotThrow()
    {
        var context = new TestDbContext();

        var e = new TestEntity { Id = Guid.NewGuid(), Name = "n1" };
        var e2 = new TestEntity { Id = Guid.NewGuid(), Name = "n2" };

        context.TestEntities.Attach(e);
        context.TestEntities.Attach(e2);

        context.Entry(e).Property(p => p.Name).IsModified = true;
        context.Entry(e2).Property(p => p.Name).IsModified = true;

        context.SaveChanges();
    }

    public class TestDbContext : DbContext
    {
        public DbSet<TestEntity> TestEntities { get; set; }

        protected override void OnConfiguring(
            DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured || optionsBuilder.Options.Extensions.Count() <= 1)
            {
                optionsBuilder.UseSqlServer("Server=.;Initial Catalog=test;User Id=sa;Password=test;TrustServerCertificate=true");

                base.OnConfiguring(optionsBuilder);
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<TestEntity>()
                .HasKey(t => t.Id);

            modelBuilder.Entity<TestEntity>()
                .HasIndex(t => new { t.Id1, t.Id2 })
                .IsUnique();
        }
    }

    public class TestEntity
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
        public Guid Id1 { get; set; }
        public Guid Id2 { get; set; }
    }

Stack trace

System.InvalidOperationException
Unable to save changes because a circular dependency was detected in the data to be saved: 'TestEntity [Modified] <-
Index { 'Id1', 'Id2' } TestEntity [Modified] <-
Index { 'Id1', 'Id2' } TestEntity [Modified]To show additional information call 'DbContextOptionsBuilder.EnableSensitiveDataLogging'.'.
   at Microsoft.EntityFrameworkCore.Utilities.Multigraph`2.ThrowCycle(List`1 cycle, Func`2 formatCycle, Func`2 formatException)
   at Microsoft.EntityFrameworkCore.Utilities.Multigraph`2.TopologicalSortCore(Boolean withBatching, Func`4 tryBreakEdge, Func`2 formatCycle, Func`2 formatException)
   at Microsoft.EntityFrameworkCore.Utilities.Multigraph`2.BatchingTopologicalSort(Func`4 tryBreakEdge, Func`2 formatCycle, Func`2 formatException)
   at Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.TopologicalSort(IEnumerable`1 commands)
   at Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.BatchCommands(IList`1 entries, IUpdateAdapter updateAdapter)+MoveNext()
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Storage.RelationalDatabase.SaveChanges(IList`1 entries)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IList`1 entriesToSave)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(StateManager stateManager, Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<>c.<SaveChanges>b__107_0(DbContext _, ValueTuple`2 t)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChanges()**
**

Include provider and version information

EF Core version:
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 7.0.202, ef core 7.0.3 (it was working fine in ef core 6.*)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. customer-reported regression Servicing-approved type-bug
Projects
None yet
Development

No branches or pull requests

3 participants