c# - 以线程安全的方式使用 DbContext 进行异步搜索
问题描述
我将 EFCore 5 与 Azure SQL Server 和 C#/WPF 前端一起使用。我正在使用 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 类上得到“在前一个操作完成之前在此上下文上启动了第二个操作”。
我最好的猜测是,因为我对 DB Repository 的搜索功能的初始调用包含在一个事件中,并且该事件在 UI 线程中触发,所以它“覆盖”了我正在使用 await 并导致第二个查询运行的事实. 我要么需要一种停止第一个查询的方法,要么需要一种确保等待得到尊重的方法。
有什么建议可以让 ToListAsync() 很好地工作,但允许 UI 感觉响应?
解决方案
我订阅了 PropertyChanged,当它被触发时,我调用我的存储库类来执行异步数据库搜索......尽管“等待”每次对数据库的异步调用,如果我输入得太快,我会得到“第二个操作已启动DbContext 类上的前一个操作完成之前的此上下文。
我最好的猜测是,因为我对 DB 存储库的搜索功能的初始调用包含在一个事件中,并且该事件在 UI 线程中触发,所以它“覆盖”了我正在使用 await 并导致第二个查询运行的事实. 我要么需要一种停止第一个查询的方法,要么需要一种确保等待得到尊重的方法。
这是问题async void
之一:调用代码很难知道异步方法何时完成。这async void PropertyChanged
实际上是导致问题的原因。
有什么建议可以让 ToListAsync() 很好地工作,但允许 UI 感觉响应?
首先,我建议像其他人评论的那样去抖动。这将减少不必要的数据库调用,尽管它不会解决这个问题。对于正确的修复,您应该有一个数据库上下文池,您的代码从中分配(并在操作完成后返回),或者只使用SemaphoreSlim
. 如果您有一个共享SemaphoreSlim
的(与您现有的位置相同的位置Context
),并await semaphore.WaitAsync();
在 db 操作之前和 db 操作semaphore.Release()
之后调用,则可以确保一次访问:
await ContextMutex.WaitAsync();
try
{
result = await Context.Where(p => (p.Surname == surname)
.OrderBy(p => p.Surname)
.Take(maxResults / sString.Length).ToListAsync();
}
finally
{
ContextMutex.Release();
}
我现在只是切换到异步。
它的一个很好的特性SemaphoreSlim
是它也适用于同步代码;您可以使用该代码调用Wait
而不是await WaitAsync
. 您应该对 的所有访问应用互斥Context
以确保正确性。
推荐阅读
- c# - svcutil 无法为自托管 wcf 服务生成接口
- android - 约束布局和滚动视图不起作用
- java - 我有一个 Selenium 脚本和 GUI。如果他们没有下载 Selenium,我如何与我的团队分享
- can-bus - 监控 CAN 报文
- vba - 访问:转到记录未正确找到记录
- javascript - 在使用 vanilla js 在 Dom 上显示元素后,通过单击窗口对象隐藏元素?
- java - 如何设置 EJB 传输的超时请求?
- azure - PWA 仅使用 JS 为 Azure 通知中心注册推送通知
- python-3.x - 如何测量脸的大小?
- linux - apt-get install upgrade 在kali linux上不起作用