wtf512
wtf512

Reputation: 4728

EntityFramework throws 'Can not start another operation while there is an asynchronous operation pending'

IRepository.cs

public interface ICommonRepository<T>
    {
        Task<int> CountAsync(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>,IOrderedQueryable<T>> orderBy = null,List<Expression<Func<T, object>>> includes = null);
    }

Repository.cs:

public class Repository<T> : IRepository<T> where T : class, new()
    {
        protected readonly MyDbContext _context;
        protected readonly ILogger<Repository<T>> _logger;
        protected readonly DbSet<T> _dbSet;

        public CommomRepository(MyDbContext context, ILogger<Repository<T>> logger)
        {
            _context = context;
            _logger = logger;

            if (_context != null)
            {
                _dbSet = _context.Set<T>();
            }
            else
            {

            }
        }

        internal IQueryable<T> _Select(Expression<Func<T, bool>> filter = null
                                    , Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null
                                    , List<Expression<Func<T, object>>> includes = null
                                    , int? pageIndex = null
                                    , int? pageSize = null)
        {
            IQueryable<T> query = _dbSet;


            if (includes != null)
            {
                query = includes.Aggregate(query, (current, include) => current.Include(include));
            }

            if (orderBy != null)
            {
                query = orderBy(query);
            }

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

            if (pageIndex != null && pageSize != null)
            {
                query = query.Skip((pageIndex.Value - 1) * pageSize.Value).Take(pageSize.Value);
            }

            return query;
        }

        public async Task<int> CountAsync(Expression<Func<T, bool>> filter = null
                        , Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null
                        , List<Expression<Func<T, object>>> includes = null)
        {
            var query = _Select(filter, orderBy, includes);
            return await query.CountAsync();
        }
}

Usage (controller):

var singleCheckTask = _Repo.CountAsync(x=> x.id== item.id); 
var nameCheckTask = _Repo.CountAsync(x=> x.name== item.name); 
var ipCheckTask = _Repo.CountAsync(x=> x.ip == item.ip); 
await Task.WhenAll(singleCheckTask, nameCheckTask, ipCheckTask);

And exception thowed:

Microsoft.EntityFrameworkCore.Query.Internal.SqlServerQueryCompilationContextFactory|ERROR|An exception occurred in the database while iterating the results of a query. System.InvalidOperationException: Can not start another operation while there is an asynchronous operation pending.

I'vs tested that if I do not use Task.whenAll, var testSingleCheck = _Repo.CountAsync(x=> x.id== item.id).Result; This would be all right.

Upvotes: 1

Views: 185

Answers (1)

Tseng
Tseng

Reputation: 64150

It's simple, you can't run queries in parallel with EF (neither EF6 nor EF Core).

One reasons for is, that EF isn't thread-safe.

EF 6 on Task-based pattern

Thread Safety

While thread safety would make async more useful it is an orthogonal feature. It is unclear that we could ever implement support for it in the most general case, given that EF interacts with a graph composed of user code to maintain state and there aren't easy ways to ensure that this code is also thread safe.

For the moment, EF will detect if the developer attempts to execute two async operations at one time and throw.

Upvotes: 3

Related Questions