实体框架异步填充GridViews

时间:2019-06-19 12:34:56

标签: c# entity-framework async-await

我有一个包含4个gridviews的表单。由于实体框架,我想用查询的对象填充这些gridview。问题在于,UI在加载时会卡住。因此,我试图使查询异步,但无法正常工作。我尝试过几种方法,但目前的解决方案如下:

        private async void SwiftCheck_Load(object sender, EventArgs e)
        {
            radGridViewLast7Days.DataSource = await MonitoringToolCore.SwiftQueries.ReturnLast7DaysAsync();
            radGridViewAmount.DataSource = await MonitoringToolCore.SwiftQueries.CompareAmountsAsync();
            radGridViewAmountBySwift.DataSource = await MonitoringToolCore.SwiftQueries.CompareAmountsByTypeAsync();
            radGridViewAmountBySender.DataSource = await MonitoringToolCore.SwiftQueries.CompareAmountsBySenderAsync();

            //Code to adapt the gridviews layout after data has been bound
            this.radGridViewAmountBySender.BestFitColumns();

        }

我将数据绑定到load事件中,因为据我了解,我无法在构造函数中使用await。 然后,由于实体框架不是线程安全的,因此我对每个任务都使用了await。因此,如果我理解正确,就无法同时启动每个任务,然后等待所有任务?

这是返回对象列表的代码之一

        public static async Task<List<MsMessage>> ReturnLast7DaysAsync()
        {
            DateTime currentDate = DateTime.UtcNow.Date.AddDays(-7);

            using (var db = new SveulumeContext())
            {

                var query = db.MsMessages
                    .Where(u => u.Created >= currentDate);

                return await query.ToListAsync();               

            }
        }

该代码可以正常工作并正确绑定gridViews,但UI在整个过程中仍会阻塞。我在做什么错了?

1 个答案:

答案 0 :(得分:1)

根据this answer,Oracle在其.NET库中不支持异步查询。因此,您执行异步LINQ的方式是正确的。只是Oracle不支持它。这就是为什么您看到查询同步运行而不是异步运行的原因。

要使代码脱离UI线程,可以使用Task.Run。我还建议在代码中添加注释,因为它看起来错误:

// Task.Run is necessary because Oracle does not support async: https://stackoverflow.com/questions/29016698/can-the-oracle-managed-driver-use-async-wait-properly/29034291#29034291
radGridViewLast7Days.DataSource = await Task.Run(() => MonitoringToolCore.SwiftQueries.ReturnLast7DaysAsync());

顺便说一句,EF确实支持多个同时查询,如果,它们每个都使用自己的数据库上下文。由于您的方法确实使用它们自己的数据库上下文,因此您可以同时加载所有这些查询:

private async void SwiftCheck_Load(object sender, EventArgs e)
{
  // Task.Run is necessary because Oracle does not support async: https://stackoverflow.com/questions/29016698/can-the-oracle-managed-driver-use-async-

  var last7DaysTask = Task.Run(() => MonitoringToolCore.SwiftQueries.ReturnLast7DaysAsync());
  var compareAmountsTask = Task.Run(() => MonitoringToolCore.SwiftQueries.CompareAmountsAsync());
  var compareAmountsByTypeTask = Task.Run(() => MonitoringToolCore.SwiftQueries.CompareAmountsByTypeAsync());
  var compareAmountsBySenderTask = Task.Run(() => MonitoringToolCore.SwiftQueries.CompareAmountsBySenderAsync());
  await Task.WhenAll(last7DaysTask, compareAmountsTask, compareAmountsByTypeTask, compareAmountsBySenderTask);
  radGridViewLast7Days.DataSource = await last7DaysTask;
  radGridViewAmount.DataSource = await compareAmountsTask;
  radGridViewAmountBySwift.DataSource = await compareAmountsByTypeTask;
  radGridViewAmountBySender.DataSource = await compareAmountsBySenderTask;

  //Code to adapt the gridviews layout after data has been bound
  this.radGridViewAmountBySender.BestFitColumns();
}