У меня есть то, что, как я думал, будет простой программой для конечных пользователей для запуска хранимой процедуры, выполнение которой может занять довольно много времени. Я думал, что смогу использовать асинхронное соединение, вызывать Begin/EndExecuteNonQuery и иметь таймер, который сообщит пользователю, что он все еще работает. Все идет нормально.
Если определенный параметр имеет значение true, вызываемая хранимая процедура будет исполнять другую хранимую процедуру в самом конце. Похоже, что когда происходит этот вторичный вызов, IsCompleted становится «истинным», даже если это не так, и программа затем блокируется в EndExecuteNonQuery до тех пор, пока не завершится второй SP. Хотя я точно не знаю, я предполагаю, что это связано с тем, что непосредственный процесс SQL завершается (поскольку ему больше нечего делать, вызов EXEC является последней строкой), но подпроцесс продолжает вызов.
Как узнать, полностью ли выполнен SP? Мне кажется, что я не совсем понимаю IAsyncResult.IsCompleted; у меня сложилось впечатление, что он становится true
, когда вызов полностью выполнен, но следующее утверждение из этой ссылки заставляет меня думать иначе:
Когда это свойство имеет значение true, вы можете предположить, что безопасно отбрасывать любые ресурсы, которые вы выделяете для использования асинхронной операцией.
Так что это может работать так, как задумано, в том смысле, что я могу безопасно отказаться от ресурсов, даже если полный SP на самом деле не выполнен. Если это так, есть ли альтернатива, чтобы узнать, когда это будет полностью сделано? Я рассматривал возможность использования обычного ExecuteNonQuery
в другом потоке (BackgroundWorker
?), но сначала я хотел бы убедиться, что ничего не упустил с BeginXxx
/EndXxx
.
Я также открыт для способа отказаться от SqlCommand, чтобы программа могла завершиться, не дожидаясь SP, поскольку этот первый SP — единственное, что действительно важно для конечного пользователя.
Использование .Net 4, MSSQL 2008 R2.
Соответствующий код:
conn = new SqlConnection(@"Server=SERVERSQL;Initial Catalog=MyDatabase;User ID=MyUser;Asynchronous Processing=true");
SqlCommand cmd = new SqlCommand("OuterProcedure", conn);
cmd.CommandType = CommandType.StoredProcedure;
//[...]
IAsyncResult asyncObj = cmd.BeginExecuteNonQuery();
int count = 0;
int finalLine = Console.CursorTop;
while (!asyncObj.IsCompleted) {
Console.SetCursorPosition(0, finalLine);
++count;
Console.WriteLine("Time taken (m:s): {0}:{1}", Math.Floor((double)count / 60), (count % 60).ToString("D2"));
System.Threading.Thread.Sleep(1000);
}
Console.WriteLine("Complete");
int results = cmd.EndExecuteNonQuery(asyncObj);