1

I would like to fill a DataTable object via a SqlDataReader and have the ability to interrupt the operation (eg via the u/i in the case a user wants to cancel a long running query).

Unfortunately, I don't see any overload of DataTable.Load() that takes a CancellationToken.

Is there a clean way to achieve this?

(My only thought is use a thread and see if Thread.Interrupt() does the trick and if not then Thread.Abort() but that seems pretty unfriendly).

3
  • it takes miliseconds to fill thousands of rows. Rather than this, you can put condition in query itself. Commented Aug 17, 2016 at 13:30
  • @DheerajRoy can you explain? i've got queries that take a LONG time to return anything including metadata. how do i put the "condition in the query"? Commented Aug 17, 2016 at 14:25
  • I think you should look into the DataTable RowChanged via the SqlDataAdapter. Commented Aug 18, 2016 at 13:31

2 Answers 2

2

You could use a Task and a cancellation token. Of course, you will have to fill the DataTable manually instead of using the Load method.

private void FillTable(CancellationToken token)
{
    var reader = new SqlDataReader();
    var dt = CreateDataTable();
    while(reader.Read() && !token.IsCancellationRequested)
    {
        var row = dt.NewRow();
        // fill row from reader....
        dt.Rows.Add(row);
    }
}

You would use this method like this :

CancellationTokenSource tokenSource = new CancellationTokenSource();
Task.Factory.StartNew(() => FillTable(tokenSource.Token), tokenSource.Token);

Then you can cancel the operation :

tokenSource.Cancel();
Sign up to request clarification or add additional context in comments.

6 Comments

fleshing it out, I guess I would want reader.ReadAsync() in my case. how do I implement CreateDataTable() when I want the metadata to be based on the query results? Thanks!
I guess you can do something like this DataTable dt = reader.GetSchemaTable(); where reader is the SqlDataReader.
... and back to blocking on slow query :-(? I've got some doozies that may take minutes to return metadata (don't ask).
Well you need your query to return something to get the schema, there's no way around this. May be you should work on optimizing your queries.
You should try @William Xifaras suggestion, i think it will do what you want to achieve..
|
0

Coupled with a SqlDataAdapter, you can handle the DataTable RowChanged event and either throw an exception or close the data adapter's connection which causes an InvalidOperationException to be thrown.

Take a look at the following example (source):

private BackgroundWorker worker;
private DataTable table;

private void button2_Click(object sender, EventArgs e)
{
  if (worker != null)
  {
    worker.CancelAsync();
  }
}

private void button1_Click(object sender, EventArgs e)
{  
  this.worker = new BackgroundWorker();
  worker.WorkerReportsProgress = true;
  worker.WorkerSupportsCancellation = true;

  worker.DoWork += new DoWorkEventHandler(worker_DoWork);
  worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);

  worker.RunWorkerAsync();
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  MessageBox.Show(this.table.Rows.Count.ToString());
}

[System.Diagnostics.DebuggerStepThrough]
void worker_DoWork(object sender, DoWorkEventArgs e)
{
  this.table = new DataTable();

  using (SqlConnection connection= new SqlConnection())
  using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM table", connection))
  {
    table.RowChanged += new DataRowChangeEventHandler(table_RowChanged); 
    da.Fill(table);        
  }
}

[System.Diagnostics.DebuggerStepThrough]
void table_RowChanged(object sender, DataRowChangeEventArgs e)
{
  if (worker.CancellationPending)
  {
    throw new ApplicationException("Canceled"); // throw a spanner in the works
  }
  Thread.Sleep(5); // Just slow things down for testing
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.