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

Вопрос

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.

Это было полезно?

Решение

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.

Другие советы

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;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top