gpt4 book ai didi

multithreading - 控制台应用程序-DbContext实例不能在OnConfiguring内部使用

转载 作者:行者123 更新时间:2023-12-03 12:59:03 25 4
gpt4 key购买 nike

我正在使用Asp.Net核心控制台应用程序和Entiy Framework核心和工作单元存储库模式。当我使用多线程功能时,出现以下错误:

DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point. This can happen if a second operation is started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.



UnitOfwork.cs

public interface IUnitOfWork : IDisposable
{
void Commit();
ApplicationDbContext GetContext();
}

public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _applicationDbContext;

public UnitOfWork(ApplicationDbContext applicationDbContext)
{
_applicationDbContext = applicationDbContext;
}

public void Commit()
{
try
{
_applicationDbContext.SaveChanges();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}

public ApplicationDbContext GetContext()
{
return _applicationDbContext;
}

public void Dispose()
{
_applicationDbContext.Dispose();
}
}

IRepository.cs

public interface IGenericRepository<T>
where T : class, IEntity
{
List<T> GetAll(Expression<Func<T, bool>> filter = null,
Func<IQueryable<T>, IOrderedEnumerable<T>> orderBy = null,
string includeProperties = "");

T FindSingle(int id);

T FindBy(Expression<Func<T, bool>> predicate, string includeProperties = "");

void Add(T toAdd);

void Update(T toUpdate);

void Delete(int id);

void Delete(T entity);
}

仓库.cs

public class GenericRepository<T> : IGenericRepository<T>
where T : class, IEntity
{
private readonly IUnitOfWork _unitOfWork;

public GenericRepository(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}

public virtual List<T> GetAll(Expression<Func<T, bool>> filter = null,
Func<IQueryable<T>, IOrderedEnumerable<T>> orderBy = null,
string includeProperties = "")
{
IQueryable<T> query = _unitOfWork.GetContext().Set<T>();

if (filter != null)
{
query = query.Where(filter);
}

foreach (string includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}

if (orderBy != null)
{
return orderBy(query).ToList();
}

return query.ToList();
}

public virtual T FindSingle(int id)
{
return _unitOfWork.GetContext().Set<T>().Find(id);
}

public virtual T FindBy(Expression<Func<T, bool>> predicate, string includeProperties = "")
{
IQueryable<T> query = _unitOfWork.GetContext().Set<T>();
foreach (string includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
return query.Where(predicate).FirstOrDefault();
}

public virtual void Add(T toAdd)
{
_unitOfWork.GetContext().Set<T>().Add(toAdd);
}

public virtual void Update(T toUpdate)
{
_unitOfWork.GetContext().Entry(toUpdate).State = EntityState.Modified;
}

public virtual void Delete(int id)
{
T entity = FindSingle(id);
_unitOfWork.GetContext().Set<T>().Remove(entity);
}

public virtual void Delete(T entity)
{
_unitOfWork.GetContext().Set<T>().Remove(entity);
}
}

商业服务;

public interface IUserService
{
void CreateUser(UserEntity userEntity, bool commit = false);
}
public class UserService : IUserService
{
private readonly IGenericRepository<UserEntity> _userRepository;
private readonly IUnitOfWork _unitOfWork;

public UserService(IUnitOfWork unitOfWork, IGenericRepository<UserEntity> userRepository)
{
_unitOfWork = unitOfWork;
_userRepository = userRepository;
}

public void CreateUser(UserEntity userEntity, bool commit = false)
{
try
{
_userRepository.Add(userEntity);

if (commit)
_unitOfWork.Commit();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}

控制台Main.cs;

class Program
{
public static ServiceProvider ServiceProvider;

static void Main(string[] args)
{
InitializeIoc();

Task.Run(() => { FuncA(); });

Task.Run(() => { FuncB(); });

Console.ReadLine();
}

private static void InitializeIoc()
{
ServiceProvider = new ServiceCollection()
.AddDbContext<ApplicationDbContext>()
.AddTransient<IUnitOfWork, UnitOfWork>()
.AddTransient(typeof(IGenericRepository<>), typeof(GenericRepository<>))
.AddTransient<IUserService, UserService>()
.BuildServiceProvider();
}

private static void FuncA()
{
var userService = ServiceProvider.GetService<IUserService>();
for (int i = 0; i < 100; i++)
{
userService.CreateUser(new UserEntity { FirstName = "FuncA_" + Guid.NewGuid(), LastName = "Last", CreatedDate = DateTime.Now }, false);
}
}
private static void FuncB()
{
var userService = ServiceProvider.GetService<IUserService>();
for (int i = 0; i < 100; i++)
{
userService.CreateUser(new UserEntity { FirstName = "FuncB_" + Guid.NewGuid(), LastName = "Last", CreatedDate = DateTime.Now }, false);
}
}
}

我怎么解决这个问题?

谢谢您的帮助。

最佳答案

问题是使用的AddDbContextApplicationDbContext注册了ServiceLifetime.Scoped,但是您没有创建范围,因此它有效地作为单例工作,因此被多个线程并发共享和访问,这导致了所讨论的异常(并且可能还有许多其他原因,因为DbContext不是线程安全)。

解决方案是使用范围,例如调用CreateScope并使用返回的对象ServiceProvider属性来解析服务:

private static void FuncA()
{
using (var scope = ServicePropvider.CreateScope())
{
var userService = scope.ServiceProvider.GetService<IUserService>();
// Do something ...
}
}

private static void FuncB()
{
using (var scope = ServicePropvider.CreateScope())
{
var userService = scope.ServiceProvider.GetService<IUserService>();
// Do something ...
}
}

关于multithreading - 控制台应用程序-DbContext实例不能在OnConfiguring内部使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52603280/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com