我关注Generic Repository Pattern in ASP.NET Core,但在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);
}
和实现类:
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;
}
服务类:
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);
}
}
在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>();
}
此代码抛出错误:
InvalidOperationException:在上一个操作完成之前,在此上下文中启动了第二个操作。不保证任何实例成员都是线程安全的。
如果我在IEnumerable
上切换回IRepository
,那么它运行正常。
知道如何让它与IQueryable
一起使用,让EF Core以正确的方式运行吗?
query = from m in query
where categoryIds.Contains(m.CategoryId)
select m;
答案 0 :(得分:3)
实体框架DbContext
不是线程安全的。您一次只能执行一个查询,否则您将获得如上所述的异常。
我认为您在同一请求中并行多次使用我们的存储库,这就是您获得异常的原因。如果不按请求创建事务,则可以简单地使存储库瞬态化。在这种情况下,将为每个服务实例创建新的存储库,您将避免并发问题。