将 Db Query Result 分成任意多个任务

Divide Db Query Result into as many tasks as I want

我想将 Db 查询结果分成任意多个任务。我能怎么做?比如我想把每300行同时给同一个进程,但是每300行必须是不同的300行。

我不知道你什么意思

I want to give every 300 rows to the same process at the same time

但是,将查询结果划分为任务列表的一种可能解决方案是:

  • 记录总数:

    var count = await context.Entities.CountAsync();
    
  • 计算您需要的数据库调用总数:

    const int take = 300;
    var dbCallsCount = Math.Ceiling((double)count / take);
    
  • 创建一个获取数据的方法(注意你不能运行通过同一个DbContext对象并行查询):

    public async Task<List<Entity>> FetchDataAsync(int page, int take)
    {
         using(var context = new DbContext("ConnectionString"))
         {
             var result = await context.Entities
                                        .AsNoTracking()
                                        .Skip((page - 1) * take) 
                                        .Take(take)
                                        .ToListAsync();
             return result;
         }
    }
    
  • 创建任务列表以获取数据:

    var taskList = new List<Task<List<Entity>>>();
    
    for(var i = 0; i < dbCallsCount; i++)
        taskList.Add(FetchDataAsync(i, take));
    
    var result = await Task.WhenAll(taskList);
    

获取数据任务列表的通用方法:

public async Task<List<Task<List<TEntity>>>> DivideDbQueryIntoTasks<TEntity>(int take) where TEntity : class 
{
    int count;
    using(var context = new DbContext("ConnectionString"))
    {
        count = await context.DbSet<TEntity>.CountAsync();
    }

    var dbCallsCount = Math.Ceiling((double)count / take);
   
    // Local function
    async Task<List<TEntity>> FetchDataAsync<TEntity>(int page, int take)
    {
        using(var context = new DbContext("ConnectionString"))
        {
            var result = await context.DbSet<TEntity>
                .AsNoTracking()
                .Skip((page - 1) * take) 
                .Take(take)
                .ToListAsync();
            
            return result;
        }
    }

    var taskList = new List<Task<List<TEntity>>>();
    for(var i = 0; i < dbCallsCount; i++)
        taskList.Add(FetchDataAsync<TEntity>(i, take));

    return taskList;
}

并这样称呼:

var tasks = await DivideDbQueryIntoTasks<MyEntity>(300);
foreach (Task<List<IdentityUser>> task in tasks)
{
    ...
}