Performing a series of SQL queries, and need to be able to cancel them from the main UI thread. What is the best approach?

StackOverflow https://stackoverflow.com/questions/14448367

Question

Currently, I have several queries that need to run in order (some create temp tables which I draw from in later queries).

The queries run in a BackgroundWorker thread, and currently if there is a CancellationPending, I break out of the method in between query calls.

However this approach is problematic as there are times when a single query can run for a long time or never returns, so I need to be able to run each query while polling for BackgroundWorker.CancellationPending.

What is the best asynchronous pattern to use in this case? I need to fill a DataTable for each query, but still have the ability to cancel if it takes too long.

Était-ce utile?

La solution

In all cases, abort cooperatively. Don't even think about using Thread.Abort.

The great Stephen Toub has written a best-practice.

TL;DR: When a timeout timer fires you complete the Task immediately and let the SQL query continue to run. You just ignore it.

Autres conseils

EDIT: The solution that ended up working for me was to use the asynchronous ADO.NET methods. BeginExecute... and EndExecute...

Here is a snippet of code that asynchronously performs a query while checking whether a BackgroundWorker has requested cancellation. The function returns true if the query ran to completion, and false if a cancellation was performed.

The code should be called from somewhere within the BackgroundWorker's DoWork function.

SqlCommand command = new SqlCommand(query, connectionObj);
IAsyncResult result = command.BeginExecuteReader();  // end async execution

// check for user cancellation while result is not complete
while (!result.IsCompleted)
{
    if (myBackgroundWorker.CancellationPending)
    {
        command.Cancel();  // cancel the existing command
        try
        {
             command.EndExecuteReader(result);  // cancel async execution
        }
        catch (SqlException e)
        {
            // will always enter here due to command.Cancel()
            // this is expected
        }

        return false;
    }

    Thread.Sleep(100);  // sleep so loop doesn't consume all the resources
}

// result is complete, do something with data
using (SqlDataReader reader = command.EndExecuteReader(result))
{
    DataTable table = new DataTable();
    table.Load(reader);
}

// do something with table
return true;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top