【发布时间】:2021-08-19 17:42:48
【问题描述】:
我正在使用带有 Azure SQL Server 和 C#/WPF 前端的 EFCore 5。我正在使用 Fody 来触发我的 PropertyChanged 事件。
我有一个自定义的实时搜索控件,其中包含一个包含搜索字符串的文本框和一个显示结果的列表框。
TextBox.Text 绑定到字符串属性“SearchString”。我订阅了 PropertyChanged,当它被触发时,我调用我的存储库类来执行异步数据库搜索(实际上在查询中我还有一些 .Where 和 .Include 子句,但已经提取了相关部分):
result = await Context.Where(p => (p.Surname == surname)
.OrderBy(p => p.Surname)
.Take(maxResults / sString.Length).ToListAsync();
return result;
然后,我将生成的列表放入同一个类中的一个属性中,该属性绑定到一个 ListBox.ItemsSource 属性。到目前为止,这在同步方面运行良好(但速度很慢)——我现在只是切换到异步。
我的问题是,尽管“等待”每个对数据库的异步调用,但如果我输入得太快,我会在 DbContext 类上得到“在前一个操作完成之前在此上下文上启动了第二个操作”。
我最好的猜测是,因为我对数据库存储库的搜索功能的初始调用包含在一个事件中,并且该事件在 UI 线程中触发,所以它“覆盖”了我正在使用 await 并导致第二次查询运行。我要么需要一种停止第一个查询的方法,要么需要一种确保等待得到尊重的方法。
有什么建议可以让 ToListAsync() 很好地工作,但让 UI 感觉响应灵敏?
【问题讨论】:
-
您应该为用户在 UI 中键入内容“消除抖动”事件,这样您就不会针对每次击键发出查询。这是一篇关于它的文章:weblog.west-wind.com/posts/2017/jul/02/…
-
也许您可以使用取消令牌。
-
去抖动系统似乎正是我正在寻找的,@MartinCostello。我通过在微控制器上的一些工作熟悉了这个概念,但没有在 Windows 桌面应用程序上考虑过它!
-
不过,问题是您的代码允许多线程访问一个上下文实例。您应该始终防止这种情况发生,而不是解决它。去抖动机制并不能保证调用是串行的。
-
@GertArnold 同意这样会更好。那么任何想法如何做到这一点?我想实际上是在显式创建的线程上进行工作,然后取消该线程是一种可能性。您可以看到仍然允许使用 async / await 的任何其他可能性?
标签: c# multithreading azure async-await entity-framework-core