同时执行两个数据库调用(使用两个 DbContext)

Sco*_*ker 2 c# task-parallel-library async-await ef-core-2.2

我需要从两个不同的结果DbContext(针对 Oracle 数据库的两个不同模式)获取结果来填充页面。我想同时执行两个数据库查询(只读,无写操作),并在完成后返回结果。问题是,我是平行世界中的连续剧人,我不了解杰克Async//Await等等TPL……

我有一个Action基本上看起来像这样的控制器:

public Task<IActionResult> Foo(MyViewModel vm)
{
  if (!ModelState.IsValid) return Task.Run(()=> (IActionResult)View(vm));

  var filter = new FilterObject(vm);
  var firstTask = _firstContext.FilterItems(filter); // returns Task<IQueryable<Items>>
  var secondTask = _secondContext.FilterItems(filter); // returns Task<IQueryable<Items>> 

  vm.Result.Clear();
  vm.Results.AddRange(firstTask.Result);
  vm.Results.AddRange(secondTask.Result);

  return Task.Run(()=> (IActionResult)View("Index", vm));
}
Run Code Online (Sandbox Code Playgroud)

我DbContext调用过滤器来完成其工作:

public class FirstContext : DbContext
{
  public DbQuery<Items> Items{get;set;}

  public Task<IQueryable<Items>> FilterItems(FilterObject filter)
  {
     filter.ApplyTo(Items.AsQueryable());
  }
}
Run Code Online (Sandbox Code Playgroud)

...我的 FilterObject 修改了 IQueryable:

public class FilterObject
{
  public Task<IQueryable<Items>> ApplyTo(IQueryable<Items> items)
  {
    return Task.Run(()=> items
      .Where(item => item.Property1.Contains(this.Property1))
      .Where(item => item.Other == this.OtherString)
       // more Where clauses ad nauseum; you get the idea
  }
}
Run Code Online (Sandbox Code Playgroud)

我这样做是否接近正确?据我了解,对数据库的调用直到AddRange方法才真正执行,因为它Task.Result是一个IQueryable- 所以这对我来说似乎是错误的:AddRange()方法将同步执行,而不是异步执行,对吗?我所做的只是构建两个查询,而不是执行它们。我猜想我需要List<Item>从 DbContext 返回 a ,这将导致每个查询实际执行...但这是我需要做的唯一更改,以便这些调用同时发生,而不互相阻塞?

一如既往,我们非常感谢任何指导。

nvo*_*igt 5

Task从您拥有的 IQueryable 中删除您的所有工作。一层太多了 把事情简单化。您有疑问。这将返回一个IQueryable<>. 然后使用ToListAsync异步方式获取结果:

public async Task<IActionResult> Foo(MyViewModel vm)
{
  if (!ModelState.IsValid) return View(vm);

  var filter = new FilterObject(vm);
  var firstTask = _firstContext.YourQueryable.ToListAsync();
  var secondTask = _secondContext.YourQueryable.ToListAsync();    

  var firstResult = await firstTask;
  var secondResult = await secondTask;

  vm.Result.Clear();
  vm.Results.AddRange(firstResult);
  vm.Results.AddRange(secondResult);

  return View("Index", vm);
}
Run Code Online (Sandbox Code Playgroud)