isxaker
@isxaker

Как остановить выполнение SqlCommand?

Пишу winforms приложение на .net 4.0. Есть задача показывать диалог ожидания с кнопкой отмены выполнения запроса во время выполнения запросов к бд.

Код формы:
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();
      }
}

Код класса, с помощью которого выполняются SqlCommand-ы :
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 btn
          LoadingFrm _lFrm = new LoadingFrm(executeQuery, () => { cts.Cancel(); });
          _lFrm.ShowDialog();
          SqlDataReader r = null;
          try
          {
              r = executeQuery.Result;
          }
          catch (AggregateException ae)
          {
          }
          catch (Exception ex)
          {
          }

          return r;
      }
}


По нажатии на кнопку отменить, я вызываю метод cts.Cancel();который в свою очередь вызывает метод command.Cancel();Проблема в том, что запрос все таки не прерывается. Через некоторое время, от sql сервера все таки приходят данные.
Вопрос: как остановить выполнение SqlCommand.ExecuteQuery()

PS: Может вы решали подобные задачи другим способом, поделитесь опытом. Задача состоит в том, чтобы показывать диалоговое окно(позволяющее отменить выполнение запроса), во время выполнения запроса. Может лучше делать с помощью BeginExecuteReader(); и EndExecuteReader();
Stackoverflow
  • Вопрос задан
  • 3879 просмотров
Пригласить эксперта
Ответы на вопрос 3
@carbon88
.NET developer/ORM developer
Cancel() не всегда отменяет запрос. он только пытается отменить. скажите как он отменит что-либо если запрос уже передан субд и она его уже выполняет?

да а зачем его отменять? если это запрос на выборку остается только проигнорировать то, что пришло. если запрос на изменение данных, то тут вам транзакции в помощь. открываете транзакцию и по завершении работы делаете коммит этой транзакции. если пользователь нажал отмену, то делаете откат транзакции и все что, вы наизменяли в приделах этой транзакции не сохранится в базе.
Ответ написан
@Sumor
Cancel пытается отменить запрос и пытается передать это на SQLServer. Если запрос длительный и состоит из отдельных шагов, и эти шаги ещё на начали исполняться, то команда прервётся. Если идёт выдача, то она тоже может прерваться.
Вам же, если вы прервались, не обязательно продолжать считывать - прерывайтесь, больше не вызывайте Read(), закрывайте reader и извещайте пользователя. При использовании BeginExecuteReader вы сможете проще организовать процесс ожидания и прерывания, но чуть сложнее процесс получения данных.

В одном проекте я поступал несколько по-другому. Я быстро получал идентификаторы объектов, релевантных запросу, а затем спокойно в отдельном потоке начитывал строчки с данными (много медленных колонок). Процесс этот контролировался мной и мог прерваться в любой момент. В качестве бонуса получается правильный прогрессбар.
Ответ написан
Комментировать
Думаю, следует почитать в сторону многопоточности (threading) и асинхронного (async/await) программирования.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы