如果您建议使用SqlCommand.Cancel(),请举例说明!
我需要在查询执行期间显示带有取消按钮的等待表单(如果用户单击此按钮,查询必须停止运行)。
我的解决方案:(。net 4)
我传递给构造函数两个参数:
以下是我的加载表格的代码:
public partial class LoadingFrm : Form
{
//task for execute query
private Task execute;
//action for cancelling task
private Action cancel;
public LoadingFrm(Task e, Action c)
{
execute = e;
cancel = c;
InitializeComponent();
this.cancelBtn.Click += this.cancelBtn_Click;
this.FormBorderStyle = FormBorderStyle.None;
this.Load += (s, ea) =>
{
//start task
this.execute.Start();
//close form after execution of task
this.execute.ContinueWith((t) =>
{
if (this.InvokeRequired)
{
Invoke((MethodInvoker)this.Close);
}
else this.Close();
});
};
}
//event handler of cancel button
private void cancelBtn_Click(object sender, EventArgs e)
{
cancel();
}
}
我的ExecuteHelper类的代码:
public class ExecuteHelper
{
public static SqlDataReader Execute(SqlCommand command)
{
var cts = new CancellationTokenSource();
var cToken = cts.Token;
cToken.Register(() => { command.Cancel(); });
Task<SqlDataReader> executeQuery = new Task<SqlDataReader>(command.ExecuteReader, cToken);
//create a form with execute task and action for cancel task if user click on button
LoadingFrm _lFrm = new LoadingFrm(executeQuery, () => { cts.Cancel(); });
_lFrm.ShowDialog();
SqlDataReader r = null;
try
{
//(1) here
r = executeQuery.Result;
}
catch (AggregateException ae)
{
}
catch (Exception ex)
{
}
return r;
}
}
但我不能停止执行SqlCommand
。经过一段时间调用ExecuteHelper.Execute(command)
的方法从sql server获取带有数据的结果(SqlDataReader)
?为什么?有人可以帮忙吗?我如何取消sqlcommand的执行?
我有另一个问题。为什么我单击我的表单的取消按钮并且cts.Cancel()被称为//(1) here
我得到executeQuery.IsCanceled = false
虽然executeQuery.Status = Faulted.
答案 0 :(得分:3)
而不是致电ExecuteReader
致电ExecuteReaderAsync
并传递CancellationToken
。
如果您使用的是.net 4.0,则可以使用ExecuteReaderAsync
编写自己的TaskCompletionSource
。我还没有测试过这段代码,但大致应该是这样:
public static class Extensions
{
public static Task<SqlDataReader> ExecuteReaderAsync(this SqlCommand command, CancellationToken token)
{
var tcs = new TaskCompletionSource<SqlDataReader>();
// whne the token is cancelled, cancel the command
token.Register( () =>
{
command.Cancel();
tcs.SetCanceled();
});
command.BeginExecuteReader( (r) =>
{
try
{
tcs.SetResult(command.EndExecuteReader(r));
}
catch(Exception ex)
{
tcs.SetException(ex);
}
}, null);
return tcs.Task;
}
}
您正在使用SqlCommand.Cancel
方法取消正在进行的任何异步操作。然后你可以像这样使用它:
public static SqlDataReader Execute(SqlCommand command)
{
SqlDataReader r = null;
var cts = new CancellationTokenSource();
var cToken = cts.Token;
var executeQuery = command.ExecuteReaderAsync(cToken).
.ContinueWith( t =>
{
if(t.IsCompleted)
{
r = t.Result;
}
}, TaskScheduler.Default);
//create a form with execute task and action for cancel task if user click on button
LoadingFrm _lFrm = new LoadingFrm(executeQuery, () => { cts.Cancel(); });
// Assuming this is blocking and that the executeQuery will have finished by then, otheriwse
// may need to call executeQuery.Wait().
_lFrm.ShowDialog();
return r;
}
我修改了Execute
方法以使用ContunueWith
而不是r.Result
,因为Result
是阻止属性,在查询之前您不会显示对话框完成。
如上所述,它是未经测试的,但应该非常接近您的需求。