EntityFramework抛出'当异步操作挂起时无法启动另一个操作'

时间:2017-04-03 05:11:05

标签: entity-framework asp.net-core entity-framework-core

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();
        }
}

用法(控制器):

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);

例外情况:

  

Microsoft.EntityFrameworkCore.Query.Internal.SqlServerQueryCompilationContextFactory | ERROR |在迭代查询结果时数据库中发生异常。   System.InvalidOperationException:在异步操作挂起时无法启动另一个操作。

我测试过,如果我不使用Task.whenAll,var testSingleCheck = _Repo.CountAsync(x=> x.id== item.id).Result;这样就可以了。

1 个答案:

答案 0 :(得分:3)

很简单,您无法与EF并行运行查询(既不是EF6也不是EF Core)。

一个原因是,EF不是线程安全的。

EF 6 on Task-based pattern

  

线程安全

     

虽然线程安全会使异步更有用,但它是一个正交特征。目前还不清楚我们是否可以在最常见的情况下实现对它的支持,因为EF与用户代码组成的图形交互以维持状态,并且没有简单的方法来确保此代码也是线程安全的。

     

目前,EF将检测开发人员是否尝试同时执行两个异步操作并抛出。