Я пишу довольно простое многопользовательское WPF-приложение, в котором каждый пользователь может изменять / удалять свои собственные данные.Означает, что каждый пользователь может видеть все данные других пользователей, но не имеет права изменять или удалять их.Все приложение работает хорошо до тех пор, пока 2 или более клиентов не попадут в метод savechanges одновременно, а затем я иногда сталкиваюсь с тупиком базы данных.
Транзакция (ID процесса 57) была заблокирована на ресурсах блокировки с другимпроцесс и был выбран в качестве жертвы тупика.Перезапустите транзакцию.
Я понятия не имею, почему возникает эта тупиковая ситуация, поскольку невозможно, чтобы разные пользователи одновременно изменяли или удаляли одни и те же данные.
Я написал короткую программу, которая демонстрирует поведение.Метод удаления в конце моделирует двух пользователей, удаляющих их собственные данные одновременно.
Вот мой DbContext и Datamodel:
public class Context : DbContext
{
public DbSet<City> dbsCities { get; set; }
public DbSet<House> dbsHouses { get; set; }
public DbSet<Person> dbsPersons { get; set; }
public Context() : base(@"Server=.\SQLExpress;Database=test;Trusted_Connection=Yes;Connection Timeout=5")
{
Configuration.AutoDetectChangesEnabled = true;
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<City>().HasMany(c => c.Houses).WithRequired(c => c.City).WillCascadeOnDelete(true);
modelBuilder.Entity<House>().HasMany(p => p.Residents).WithRequired(p => p.House).WillCascadeOnDelete(true);
}
}
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();
}
}
А вот код для генерации тестовых данных:
using (Context ctx = new Context())
{
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.dbsCities.AddRange(cities);
ctx.SaveChanges();
}
Наконец метод, который вызывает тупик
private void Delete(object sender, RoutedEventArgs e)
{
string[] to = new string[] {"A", "B"};
Parallel.ForEach(to, code =>
{
DeleteHouses(code);
});
}
private void DeleteHouses(string code)
{
using (var ctx = new Context())
{
ctx.Database.Log += Console.WriteLine;
var todel = ctx.dbsHouses.Where(d=>d.Code == code);
if (todel != null)
{
ctx.dbsHouses.RemoveRange(todel);
ctx.SaveChanges();
}
}
}
Понятия не имею, почему это заходит в тупик, есть идеи, что я делаю неправильно?