gpt4 book ai didi

c# - EF6 ToListAsync() 取消长查询不起作用

转载 作者:行者123 更新时间:2023-12-03 12:52:22 27 4
gpt4 key购买 nike

我正在开发 Entity Framework WinForms 应用程序,并尝试在与 UI 分开的线程上运行查询,并允许用户取消长查询。
我有 already asked one question关于如何正确实现这一点并且在那里可能仍然不正确,但我目前的问题是如何允许用户取消长时间运行的 EF6 查询?

我找到了 this 的链接。 ,但似乎仍然无法正常工作...再次,可能是我将原始部分编程错误(从我的第一个问题开始),但我的问题是如何允许用户单击取消按钮那会停止对数据库的长时间查询吗?

我的(相关)当前代码如下......

Private cts As New CancellationTokenSource

Private Sub Cancel_Click(sender As Object, e As EventArgs) Handles Cancel.Click
cts.Cancel()
End Sub

尝试 1(在任务中添加取消标记):
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

Dim y As New List(Of DBData)

Try
Var1 = "Var1"

Dim qry As Task(Of List(Of DBData)) = Task.Run(Function() GetDBData(Var1), cts.Token))

Try
y = Await qry
cts.Token.ThrowIfCancellationRequested()
Catch ex As OperationCanceledException
' ** ONLY REACH HERE AFTER QUERY PROCESSES!! **
End Try
End Sub

尝试 2(在 EF ToListAsync() 方法中添加取消 token ):
Private Async Function GetDBData(Var1 As String, ct As CancellationToken) As Task(Of List(Of DBData))

Dim retval As List(Of DBData)

Using x As New DBContext
Try
retval = Await (From rw In x.DBData
Where rw.Val1= Val1
Select rw).ToListAsync(ct)
ct.ThrowIfCancellationRequested()

Return retval

Catch ex As Exception
' ** ONLY REACH HERE AFTER QUERY PROCESSES!! **
MsgBox(ex.Message)
Return Nothing
End Try
End Using

End Function

我希望我发布的解释/代码对两者之间的差异有意义......任何帮助将不胜感激! - 即使这是在 VB 中,我对 VB/C# 解决方案也同样满意。

谢谢!!

最佳答案

遗憾的是,EF 团队从未修复过这个错误。

事实上,这是整个 EF 6 Async 实现的一个整体弱点。

开发团队已尽最大努力通过使用内部类 InternalContext 等抽象出对底层 SqlCommand 的任何访问。

他们没有做的是将您的 CancellationToken 的 Cancel() 操作连接到 SqlCommand.Cancel。这是一个明显的错误,非常令人沮丧。

如果您的查询返回行,那么它们的代码可以工作,因为任务将在迭代后返回,但这是一项非常糟糕的工作。

internal static Task<List<T>> ToListAsync<T>(this IDbAsyncEnumerable<T> source, CancellationToken cancellationToken)
{
TaskCompletionSource<List<T>> tcs = new TaskCompletionSource<List<T>>();
List<T> list = new List<T>();
IDbAsyncEnumerableExtensions.ForEachAsync<T>(source, new Action<T>(list.Add), cancellationToken).ContinueWith((Action<Task>) (t =>
{
if (t.IsFaulted)
tcs.TrySetException((IEnumerable<Exception>) t.Exception.InnerExceptions);
else if (t.IsCanceled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(list);
}), TaskContinuationOptions.ExecuteSynchronously);
return tcs.Task;
}

这可以通过向 IDbAsyncEnumerable 添加逻辑以处理取消或创建新接口(interface) IDbCancellableAsyncEnumerable 来解决,即公开一个 Cancel 方法的类,该方法在内部访问正在执行的 SqlCommand 并调用 Cancel。

由于他们没有为此烦恼,我怀疑这不会很快发生,因为这可能需要做很多工作。

注意:即使您尝试使用 ExecuteSqlCommandAsync(),您仍然无法杀死 SqlCommand。

关于c# - EF6 ToListAsync() 取消长查询不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25387636/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com