简体   繁体   English

实体框架核心线程安全吗?

[英]Entity Framework Core thread safe?

I follow Generic Repository Pattern in ASP.NET Core , but on IRepository , I use IQueryable instead of IEnumerable : 我遵循ASP.NET Core中的Generic Repository Pattern ,但在IRepository ,我使用IQueryable而不是IEnumerable

public  interface IRepository<T> where T: BaseEntity
{
    IQueryable<T> Table { get; }
    IEnumerable<T> TableNoTracking { get; }
    T Get(long id);
    void Insert(T entity);
    void Update(T entity);
    void Delete(T entity);
}

and implementation class: 和实现类:

    public class EFRepository<T> : IRepository<T> where T : BaseEntity
    {
        private readonly ApplicationDbContext _ctx;
        private DbSet<T> entities;
        string errorMessage = string.Empty;

        public EFRepository(ApplicationDbContext context)
        {
            this._ctx = context;
            entities = context.Set<T>();
        }

        public virtual IQueryable<T> Table => this.entities;
    }

Service class: 服务类:

public class MovieService : IMovieService
{
        private readonly IRepository<MovieItem> _repoMovie;

        public MovieService(IRepository<MovieItem> repoMovie)
        {
            _repoMovie = repoMovie;
        }

        public async Task<PaginatedList<MovieItem>> GetAllMovies(int pageIndex = 0, int pageSize = int.MaxValue,
               IEnumerable<int> categoryIds = null)
        {
            var query = _repoMovie.Table;

            if (categoryIds != null)
            {
                query = from m in query
                        where categoryIds.Contains(m.CategoryId)
                        select m;
            }

            return await PaginatedList<MovieItem>.CreateAsync(query, pageIndex, pageSize);
        }
}

On Startup.cs: 在Startup.cs上:

  public void ConfigureServices(IServiceCollection services)
  {
        // Add framework services.
        services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.AddMvc();
        services.AddScoped(typeof(IRepository<>), typeof(EFRepository<>));           
        services.AddTransient<IMovieService, MovieService>();
        services.AddTransient<ICategoryService, CategoryService>();
    }

This code throws an error: 此代码抛出错误:

InvalidOperationException: A second operation started on this context before a previous operation completed. InvalidOperationException:在上一个操作完成之前,在此上下文中启动了第二个操作。 Any instance members are not guaranteed to be thread safe. 任何实例成员都不保证是线程安全的。

If I switch back to IEnumerable on IRepository , then it runs fine. 如果我在IRepository上切换回IEnumerable ,那么它运行正常。

Any idea how to get it to work with IQueryable , to make to EF Core to run in the right way ? 知道如何让它与IQueryable ,让EF Core以正确的方式运行吗?

query = from m in query
        where categoryIds.Contains(m.CategoryId)
        select m;

Entity Framework DbContext is not thread safe. 实体框架DbContext不是线程安全的。 You can execute only one query at a time otherwise you will get an exception like you did above. 您一次只能执行一个查询,否则您将获得如上所述的异常。

I suppose that you use our repository multiple times during same request in parallel that's why you get the exception. 我想你在同一个请求中并行多次使用我们的存储库,这就是你得到异常的原因。 If you don't create a transaction per request you can simply make repository transient. 如果不按请求创建事务,则可以简单地使存储库瞬态化。 In this case new repository will be created fro each instance of your service and you will avoid concurrency issue. 在这种情况下,将为每个服务实例创建新的存储库,您将避免并发问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM