Я использую Ef6 в приложении .net web Api.Это устаревший монолит, который мы пытаемся преобразовать в архитектуру микросервиса CQRS.В настоящее время мы сталкиваемся с проблемами параллелизма с использованием EF6, и я понятия не имею, как решить эту проблему.Для начала у меня есть две базы данных (запись и чтение).Мы используем SQL Server 2012 в качестве RDBMS.Я использую IOC / DI с Autofac и, поскольку у нас есть 2 дБ, я хотел создать 2 различных объекта контекста, и вот как выглядит код.
// Конструктор Unit of Work
public UnitOfWork(IContext readContext, IContext writeContext, IMapper
mapper)
{
_readContext = readContext;
_writeContext = writeContext;
_mapper = mapper; //this is for the automapper
}
Это создает 2 объекта контекста из интерфейса IContext.
// Интерфейс IContext имеет 2 пользовательских объекта контекста следующим образом
public partial class MyWriteContext : IContext,IDisposable
{
}
public partial class MyReadContext : IContext,IDisposable
{
}
Мы специально создали эти 2 класса как частичные, поскольку это те же имена, которые мы используем для создания фактического Ef6dbcontexts
// Объекты контекста Actual Entity Framework, сгенерированные с помощью обратного poco
public partial class EfWriteContext : DbContext{}
partial class EFReadContext : DbContext{}
Это моя конфигурация Autofac для одного и того же dbcontext, единицы работы и общего хранилища, все они определены в модулях autofac и зарегистрированы иразрешается в веб-API Startup.cs
// Модуль регистрации контекстного автофака
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<MyReadContext>()
.Named<IContext>("MyReadContext")
.InstancePerDependency();
builder.RegisterType<MyWriteContext>()
.Named<IContext>("MyWriteContext")
.InstancePerDependency();
}
protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration)
{
registration.Preparing -= Registration_Preparing;
registration.Preparing += Registration_Preparing;
}
private void Registration_Preparing(object sender, PreparingEventArgs e)
{
Parameter parameter = new ResolvedParameter(
(pi, c) => pi.ParameterType == typeof(IContext),
(pi, c) =>
{
if (pi.Name.Equals("readContext", StringComparison.OrdinalIgnoreCase))
{
return c.ResolveNamed<IContext>("MyReadContext");
}
else if (pi.Name.Equals("writeContext", StringComparison.OrdinalIgnoreCase))
{
return c.ResolveNamed<IContext>("MyWriteContext");
}
else
{
return c.ResolveNamed<IContext>("MyReadContext");
}
});
e.Parameters = e.Parameters.Concat(new Parameter[] { parameter });
}
// Единица работы
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerDependency();
// Хранилище
builder.RegisterAssemblyTypes(Assembly.Load("Infrastructure"))
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces()
.InstancePerDependency();
// Конструктор репозитория
public Repository(IContext dbContext)
{
context = dbContext;
_dbset = context.Set<TEntity>();
}
Этот код отлично работает и вставляет и обновляет данные в случае использования одного пользователя при вызове writecontext.SaveChanges ().Это даже работает, если несколько пользователей имеют временной интервал между ними при сохранении данных в БД, но проблема возникает, когда 2 пользователя фактически пытаются сохранить данные в БД одновременно.Затем он начинает выдавать ошибки
Аргумент 'entitySetName' не может быть нулевым, пустым или содержать только пробел.
Элемент уже существует вмодель.
Нарушение ограничения ПЕРВИЧНЫЙ КЛЮЧ.Невозможно вставить дубликат ключа в объект.Дубликат значения ключа (0, 4862).Оператор был прерван.
, а затем последующие вызовы также начинают сбой для всех пользователей.