Добрый день, на основе своих задач я сделал этот синтетический пример.
Есть класс А, у которого есть класс Б, у которого есть класс С.
public class A
{
public Guid Id { get; set; }
public List Bs { get; set; } = [];
public string Name { get; set; }
}
public class B
{
public Guid Id { get; set; }
public Guid AId { get; set; }
public A A { get; set; }
public List Cs { get; set; } = [];
}
public class C
{
public Guid Id { get; set; }
public Guid BId { get; set; }
public B B { get; set; }
public string Name { get; set; }
}
Приходит запрос на изменение класса А. Условиями для этого являются то, что у него должно быть три класса В, в каждом классе В должен быть один класс С, имя которого начинается со строчной буквы.
p>
Я использую postgres + ef core 8
MainDbContext db1 = ...;
A a = db1.A.first ...;
await using var t1 = await db1.Database.BeginTransactionAsync(IsolationLevel.ReadUncommitted);
a.Name = "Anew";
await db1.SaveChangesAsync();
if (db1.As.Any(m => m.Id == aId && m.Bs.Count() == 3 && m.Bs.All(n => n.Cs.Count == 1 && n.Cs.First().Name == "c")))
await t1.CommitAsync();
else
await t1.RollbackAsync();
теперь узким местом является временной интервал между фиксацией и откатом.
Поскольку какой-то другой процесс может нарушить удаление/добавление класса B или класса C или изменение класса C, что приведет к ложное условие
Как решить эту проблему? Заранее спасибо.
Я мало что знаю о SQL и уровнях изоляции, возможно, у меня неправильное представление о некоторых базовых вещах.
Я попробовал уровень изоляции синхронизации. Но чтобы это работало, другие запросы также должны выполняться на уровне изоляции синхронизации.
Вот весь код, который я тестирую.
using System.Data;
using System.Data.Common;
using System.Text.RegularExpressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext(m => m.UseNpgsql(builder.Configuration.GetConnectionString("DB")));
var app = builder.Build();
var db1 = app.Services.CreateScope().ServiceProvider.GetRequiredService();
var db2 = app.Services.CreateScope().ServiceProvider.GetRequiredService();
var db3 = app.Services.CreateScope().ServiceProvider.GetRequiredService();
await db3.Database.EnsureCreatedAsync();
await db3.Database.EnsureDeletedAsync();
await db3.Database.MigrateAsync();
var aId = Guid.NewGuid();
db3.As.Add(new A()
{
Id = aId,
Name = "A",
Bs =
[
new B()
{
Cs =
[
new C()
{
Name = "c"
}
]
},
new B()
{
Cs =
[
new C()
{
Name = "c"
}
]
},
new B()
{
Cs =
[
new C()
{
Name = "c"
}
]
}
]
});
await db3.SaveChangesAsync();
if (Equals(db1, db2))
throw new InvalidOperationException();
await using var t1 = await db1.Database.BeginTransactionAsync(IsolationLevel.ReadUncommitted);
await using var t2 = await db2.Database.BeginTransactionAsync(IsolationLevel.ReadUncommitted);
var aFromDb1 = await db1.As.Include(m => m.Bs).FirstAsync();
var aFromDb2 = await db2.As.Include(m => m.Bs).FirstAsync();
aFromDb1.Name = "Anew";
await db1.SaveChangesAsync();
db2.Cs.Where(m=> m.BId == db2.Bs.First().Id).ExecuteDelete();
await t2.CommitAsync();
if (db1.As.Any(m => m.Id == aId && m.Bs.Count() == 3 && m.Bs.All(n => n.Cs.Count == 1 && n.Cs.First().Name == "c")))
await t1.CommitAsync();
else
await t1.RollbackAsync();
return;
public class MainDbContext : DbContext
{
public DbSet As { get; set; }
public DbSet Bs { get; set; }
public DbSet Cs { get; set; }
public MainDbContext(DbContextOptions dbContextOptions) : base(dbContextOptions)
{
}
}
public class A
{
public Guid Id { get; set; }
public List Bs { get; set; } = [];
public string Name { get; set; }
}
public class B
{
public Guid Id { get; set; }
public Guid AId { get; set; }
public A A { get; set; }
public List Cs { get; set; } = [];
}
public class C
{
public Guid Id { get; set; }
public Guid BId { get; set; }
public B B { get; set; }
public string Name { get; set; }
}
Подробнее здесь: https://stackoverflow.com/questions/788 ... oncurrency