Skip to content

Stack overflow when saving multiple modified entities with the same key #23043

Closed
@maliming

Description

@maliming

EF Core version: 5.0.0-rc.2.20475.6
Database provider: Microsoft.EntityFrameworkCore.Sqlite
Target framework: net5.0

Example.csproj

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net5.0</TargetFramework>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.0-rc.2.20475.6" />
    </ItemGroup>
</Project>

Program.cs

public class BloggingContext : DbContext
{
      private DbConnection _connection;

      public DbSet<Blog> Blogs { get; set; }
      public DbSet<Post> Posts { get; set; }

      protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
      {
            optionsBuilder.UseSqlite(CreateDatabaseAndGetConnection());
      }

      private DbConnection CreateDatabaseAndGetConnection()
      {
            _connection = new SqliteConnection("Data Source=:memory:");
            _connection.Open();

            using (var context = new BloggingContext())
            {
                  context.GetService<IRelationalDatabaseCreator>().CreateTables();
            }

            return _connection;
      }

      public override void Dispose()
      {
            base.Dispose();
            _connection.Dispose();
      }
}

public class Blog
{
      public int BlogId { get; set; }
      public string Url { get; set; }
      public List<Post> Posts { get; set; }
}

public class Post
{
      public int PostId { get; set; }
      public string Title { get; set; }

      public int BlogId { get; set; }
}

class Program
{
      static void Main(string[] args)
      {
            using (var db = new BloggingContext())
            {
                  db.Database.Migrate();
            }

            using (var db = new BloggingContext())
            {
                  var blog = new Blog
                  {
                        BlogId = 1,
                        Url = "http://sample.com",
                        Posts = new List<Post>()
                        {
                              new Post()
                              {
                                    PostId = 1,
                                    Title = "title1"
                              },
                              new Post()
                              {
                                    PostId = 2,
                                    Title = "title2"
                              }
                        }
                  };

                  db.Blogs.Add(blog);
                  db.SaveChanges();
            }

            using (var db = new BloggingContext())
            {
                  var blog = db.Blogs.Include(x => x.Posts).First(x => x.BlogId == 1);

                  blog.Posts.Clear();

                  blog.Posts.AddRange(new List<Post>()
                  {
                        new Post()
                        {
                              PostId = 1,
                              Title = "title1"
                        },
                        new Post()
                        {
                              PostId = 2,
                              Title = "title2"
                        }
                  });

                  db.SaveChanges();
            }


            Console.WriteLine("Hello World!");
      }
}

dotnet build

C:\Example>dotnet build
Microsoft (R) Build Engine version 16.8.0-preview-20475-05+aed5e7ed0 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.

  Determining projects to restore...
  All projects are up-to-date for restore.
  You are using a preview version of .NET. See: https://aka.ms/dotnet-core-preview
  Example -> C:\Example\bin\Debug\net5.0\Example.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.83

dotnet run

C:\Example>dotnet run
Stack overflow.

It seems that the AcceptChanges method caused the endless loop.

SharedIdentityEntry?.AcceptChanges();

public virtual void AcceptChanges()

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions