如何在实体框架操作期间使应用程序响应

本文关键字:应用程序 响应 操作 实体 框架 | 更新日期: 2023-09-27 18:20:29

我有一个相当简单的WPF应用程序,它使用实体框架。应用程序的主页面有一个记录列表,我在启动时从数据库中获取这些记录。

每条记录都有一张图片,因此当无线信号较差时,操作可能会有点慢。如果可能的话,我希望这(以及我的许多SQL操作)在后台执行。我有async/await设置,起初它似乎完全按照我的意愿工作,但现在我发现我的应用程序在访问数据库时变得没有响应。

最终,我想我会在一个查询中加载文本,在另一个后台操作中加载图像,并在它们进入时加载它们。这样,我可以立即获得重要的东西,图片也可以进入后台,但从目前的情况来看,如果我这样做,它看起来仍然会锁定。

除此之外,我正在尝试实现一些处理连接问题的方法(以防wifi暂时中断),以便应用程序通知用户连接问题,自动重试几次,等等。我为SQL异常设置了一个try-catch,它似乎对我有效,但整个应用程序在尝试连接到数据库时会锁定大约一分钟。

我尝试使用await Task.Delay()测试我的async/await,在等待延迟时,一切都像预期的那样响应,但在等待.ToListAsync()时,一切就锁定了。这是正常的和预期的吗?我对async/await的理解非常有限。

我的代码有点乱(我是新手),但它在很大程度上完成了我需要它做的事情。我知道我可能有很多改进和更好的做事方式,但在这里一步一个脚印。我现在的主要目标是防止应用程序在数据库访问异常期间崩溃,并通知用户应用程序正在做什么(搜索、尝试访问数据库、无法访问数据库和重试等),而不是被冻结,这是他们看到应用程序在一分钟以上没有响应时会想到的。

我的一些代码:

在我的主视图模型中

DataHelper data = new DataHelper();
private async void GetQualityRegisterQueueAsync()
    {
        try
        {
            var task = data.GetQualityRegisterAsync();
            IsSearching = true;
            await task;
            IsSearching = false;
            QualityRegisterItems = new ObservableCollection<QualityRegisterQueue>(task.Result);
            OrderQualityRegisterItems();
        }
        catch (M1Exception ex)
        {
            Debug.WriteLine(ex.Message);
            Debug.WriteLine("QualityRegisterLogViewModel.GetQualityRegisterQueue() Operation Failed");
        }
    }

我的数据助手类

public class DataHelper
{
    private bool debugging = false;
    private const int MAX_RETRY = 2;
    private const double LONG_WAIT_SECONDS = 5;
    private const double SHORT_WAIT_SECONDS = 0.5;
    private static readonly TimeSpan longWait = TimeSpan.FromSeconds(LONG_WAIT_SECONDS);
    private static readonly TimeSpan shortWait = TimeSpan.FromSeconds(SHORT_WAIT_SECONDS);
    private enum RetryableSqlErrors
    {
        ServerNotFound = -1,
        Timeout = -2,
        NoLock = 1204,
        Deadlock = 1205,
    }
    public async   Task<List<QualityRegisterQueue>> GetQualityRegisterAsync()
    {
       if(debugging) await Task.Delay(5000);
       var retryCount = 0;
       using (M1Context m1 = new M1Context())
       {
           for (; ; )
           {
               try
               {
                   return await (from a in m1.QualityRegisters
                                 where (a.qanClosed == 0)
                                 //orderby a.qanAssignedDate descending, a.qanOpenedDate
                                 orderby a.qanAssignedDate.HasValue descending, a.qanAssignedDate, a.qanOpenedDate
                                 select new QualityRegisterQueue
                                 {
                                     QualityRegisterID = a.qanQualityRegisterID,
                                     JobID = a.qanJobID.Trim(),
                                     JobAssemblyID = a.qanJobAssemblyID,
                                     JobOperationID = a.qanJobOperationID,
                                     PartID = a.qanPartID.Trim(),
                                     PartRevisionID = a.qanPartRevisionID.Trim(),
                                     PartShortDescription = a.qanPartShortDescription.Trim(),
                                     OpenedByEmployeeID = a.qanOpenedByEmployeeID.Trim(),
                                     OpenedByEmployeeName = a.OpenedEmployee.lmeEmployeeName.Trim(),
                                     OpenedDate = a.qanOpenedDate,
                                     PartImage = a.JobAssembly.ujmaPartImage,
                                     AssignedDate = a.qanAssignedDate,
                                     AssignedToEmployeeID = a.qanAssignedToEmployeeID.Trim(),
                                     AssignedToEmployeeName = a.AssignedEmployee.lmeEmployeeName.Trim()
                                 }).ToListAsync();
               }
               catch (SqlException ex)
               {
                   Debug.WriteLine("SQL Exception number = " + ex.Number);
                   if (!Enum.IsDefined(typeof(RetryableSqlErrors), ex.Number))
                       throw new M1Exception(ex.Message, ex);
                   retryCount++;
                   if (retryCount > MAX_RETRY) throw new M1Exception(ex.Message, ex); ;
                    Debug.WriteLine("Retrying. Count = " + retryCount);
                   Thread.Sleep(ex.Number == (int)RetryableSqlErrors.Timeout ?
                                                           longWait : shortWait);
               }
           }
       }

    }

}

编辑:主要是在这里寻找一般指导,尽管有一个具体的例子来说明该怎么做会很好。对于我下载数据的这些类型的操作,如果我需要应用程序进行响应,我是否需要创建多个线程?这是解决这类问题的常用方法吗?这不是我应该期待async/await解决的问题吗?

如何在实体框架操作期间使应用程序响应

如果从UI线程调用此方法,则会重载UI线程上下文的捕获并返回到其本身。此外,您的服务不一定是"Performant",因为它必须等到UI线程空闲后才能继续。

解决方案很简单:只需在进行调用时调用传递ConfigureAwait"false"参数的方法。

.ToListAsync().ConfigureAwaiter(false);

我希望它能帮助