使用EF6从数据库中选择大量数据异步

时间:2015-02-12 08:50:29

标签: c# .net entity-framework asynchronous async-await

我要做的是从一个表中获取大约400万行的行来为ElasticSearch索引它。

底层索引器将使用IndexManyAsync并批量处理给它的可枚举。

类似的东西:

public void IndexMany(IEnumerable<IIndexModel> indexModels) {
    var client = new ElasticClient(settings);
    var batches = indexModels.Batch(1000);
    var tasks = new List<Task>();
    Parallels.ForEach(partitions, partition =>
    {
        var task = client.IndexManyAsync(partition);
        tasks.Add(task);
    }

    Task.WaitAll(tasks.ToArray());
}

所以考虑到这一点我想用IndexModels创建一个可枚举的。

IndexModels将获取一个实体并通过给定实体初始化各种属性。类似的东西:

public class FooModel<T> : IIndexModel
{
    public FooModel(T entity) 
    {
        Name = entity.Name;
    }

    public string Name { get; set; }
}

我有一个包含~4mil行的表,显然需要一些时间来查询。所以我想做的就是做这个异步。

我尝试了各种方法。第一种方法是批量查询并对其进行相似的操作。这给ObjectContext带来了各种并发问题。

public void IndexAllModels() {
    using (var db = new Db()) {
        var batchedEntities = db.BigTable.Select(p => p).Batch(1000);

        Parallels.ForEach(batchedEntities, currentBatch =>
        {
            var indexModels = new List<IIndexModel>();
            foreach (var entity in currentBatch) 
            {
                var indexModel = new FooModel<BigTable>(entity);
                indexModels.Add(indexModel);
            }

            IndexMany(indexModels);
        }
    }
}

我想知道是否有任何方法可以通过使用新的EF6异步操作来实现这一点?

1 个答案:

答案 0 :(得分:2)

使用自然async API的优点是您不需要使用线程来使用它们。从一直到WinAPI级别There Is No Thread

您可以创建一个采用IEnumerable<IndexModel>并使用ElasticSearchs异步API的方法,如下所示:

public async Task IndexManyAsync(IEnumerable<IIndexModel> indexModels) 
{
    var client = new ElasticClient(settings);

    var taskBatches = indexModels.Batch(1000)
                                 .Select(partition =>
                                         client.IndexManyAsync(partition));

    await Task.WhenAll(taskBatches);
}

假设IndexManyAsync为每个请求使用单独的DbContext,这应该可以。