Skip to content

Deadlock when concurrently deleting disjoint graphs with two levels of cascade #15180

Description

@divega

Cross-posting from dotnet/ef6#723 (comment) since the behavior repros for both EF6 and EF Core.

Note that this may be a duplicate of #14371. The models look very similar, however the repro in that case:

  • Was alternatively inserting and deleting data, while on this one it only deletes
  • Would deadlock in every other request, while on this one it deadlocks every time
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;

namespace EF6Issue723
{
    class Program
    {
        static void Main(string[] args)
        {

            using (Context ctx = new Context())
            {
                ctx.Database.EnsureDeleted();
                ctx.Database.EnsureCreated();
                List<City> cities = new List<City>() { new City() { Name = "New York" } };
                for (int h = 1; h <= 50; h++)
                {
                    string code = "A";
                    if (h % 2 == 0)
                        code = "B";
                    House house = new House() { Number = h, Code = code };
                    cities[0].Houses.Add(house);
                    for (int i = 0; i <= 100; i++)
                        house.Residents.Add(new Person() { Firstname = "A", Lastname = "B" });
                }

                ctx.Cities.AddRange(cities);
                ctx.SaveChanges();
            }

            string[] to = new string[] { "A", "B" };
            Parallel.ForEach(to, code =>
            {
                DeleteHouses(code);
            });
        }

        private static void DeleteHouses(string code)
        {
            using (var ctx = new Context())
            {
                var todel = ctx.Houses.Where(d => d.Code == code);
                if (todel != null)
                {
                    ctx.Houses.RemoveRange(todel);
                    ctx.SaveChanges();
                }
            }
        }


    }

    public class Context : DbContext
    {
        public DbSet<City> Cities { get; set; }
        public DbSet<House> Houses { get; set; }
        public DbSet<Person> Persons { get; set; }

        public Context() : base()
        {
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=test;Trusted_Connection=Yes;ConnectRetryCount=0");

        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<City>().HasMany(c => c.Houses).WithOne(c => c.City).IsRequired().OnDelete(DeleteBehavior.Cascade);
            modelBuilder.Entity<House>().HasMany(p => p.Residents).WithOne(p => p.House).IsRequired().OnDelete(DeleteBehavior.Cascade);
        }
    }

    public class City
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
        public virtual ICollection<House> Houses { get; set; }

        public City()
        {
            Id = Guid.NewGuid();
            Houses = new List<House>();
        }
    }

    public class House
    {
        public Guid Id { get; set; }
        public int Number { get; set; }
        public string Code { get; set; }
        public virtual City City { get; set; }
        public virtual ICollection<Person> Residents { get; set; }

        public House()
        {
            Id = Guid.NewGuid();
            Residents = new List<Person>();
        }
    }


    public class Person
    {
        public Guid Id { get; set; }
        public string Firstname { get; set; }
        public string Lastname { get; set; }

        public virtual House House { get; set; }

        public Person()
        {
            Id = Guid.NewGuid();
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions