我如何从.net代码停止sql查询执行?

时间:2014-07-02 10:05:59

标签: c# sql .net task sqlcommand

如果您建议使用SqlCommand.Cancel(),请举例说明!

我需要在查询执行期间显示带有取消按钮的等待表单(如果用户单击此按钮,查询必须停止运行)。

我的解决方案:(。net 4)

我传递给构造函数两个参数:

  1. 查询执行任务
  2. 取消行动
  3. 以下是我的加载表格的代码:

    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.

1 个答案:

答案 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是阻止属性,在查询之前您不会显示对话框完成。 如上所述,它是未经测试的,但应该非常接近您的需求。