【问题标题】:How i can stop sql query execution from .net code? [duplicate]我如何停止从.net 代码执行 sql 查询? [复制]
【发布时间】:2014-07-02 10:05:58
【问题描述】:

如果您推荐使用 SqlCommand.Cancel(),请给出一个工作示例!

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

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

我向表单构造函数传递了两个参数:

  1. 查询执行任务
  2. 取消操作

下面是我的加载表单代码:

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.

【问题讨论】:

  • @Liath,因为该链接无法帮助我解决问题
  • @Liath,你可以给出工作代码,通过 SqlCommand 的 Cancel 方法停止执行查询?
  • 我尝试了这个解决方案,没有成功。

标签: c# sql .net task sqlcommand


【解决方案1】:

而不是调用ExecuteReader 调用ExecuteReaderAsync 并传入CancellationToken

如果您使用的是 .net 4.0,您可以使用 TaskCompletionSource 编写自己的 ExecuteReaderAsync。这段代码我没有测试过,但大致应该是这样的:

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

【讨论】:

  • .net 4 没有 ExecuteReaderAsync
  • 只有 BeginExecuteReader 和 EndExecuteReader
  • 您可以使用Task.FromAsync 自己制作一个。我会发布一些代码。
  • 我已经更新了答案,希望对您有所帮助。
  • 尝试将executeQuery变量的类型更改为var
猜你喜欢
  • 2011-06-14
  • 2013-02-14
  • 1970-01-01
  • 1970-01-01
  • 2011-03-31
  • 2013-10-12
  • 1970-01-01
  • 2014-02-22
相关资源
最近更新 更多