I follow Generic Repository Pattern in ASP.NET Core, but on IRepository
, I use IQueryable
instead of 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:
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. Any instance members are not guaranteed to be thread safe.
If I switch back to IEnumerable
on IRepository
, then it runs fine.
Any idea how to get it to work with IQueryable
, to make to EF Core to run in the right way ?
query = from m in query
where categoryIds.Contains(m.CategoryId)
select m;
Entity Framework DbContext
is not thread safe. 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With