Асинхронные вызовы SQL в ADO.NET

ОГЛАВЛЕНИЕ

Как использовать асинхронные вызовы SQL, чтобы получать сообщения о ходе работы

Введение

Данная статья показывает, как использовать асинхронные вызовы в ADO.NET, чтобы получать сообщения о ходе работы от вызовов хранимых процедур, выполняющихся в течение длительного периода времени, или любых других команд SQL, которые порождают сообщения для клиента (пользователя).

Нашей первоначальной идеей было показать, как вы можете ретранслировать клиенту сообщения оператора  SQL BACKUP, но если у вас нет достаточно большой базы данных, вы не заметите проблему, о которой мы расскажем. Нет существенного различия между выполнением хранимой процедуры и команды BACKUP, обе отправляют свои информационные сообщения как ошибки (которыми они не являются). Обе используют RAISERROR с NOWAIT, из которой мы можем принимать сообщения. Мы предполагаем, что BACKUP имеет другой метод для возврата информационных сообщений. Для хранимых процедур есть только команда RAISERROR.

Это хорошо, поскольку есть флаг серьезности ошибки, являющийся частью вызова, и любое значение серьезности, меньшее 10, используется только для информации (смотрите документацию MSDN). Так что можно использовать значение серьезности для наших целей.

Почему вы хотите это сделать?

Мы обычно используем это для одной из хранимых процедур, которые сильно изменяют базу данных, обновляют базу данных, или для BACKUP, которые запускаются из сервисной программы клиента, где они ожидают увидеть сообщения о том, что процедура не остановилась и продолжает выполняться!

Используемая хранимая процедура

Следующая хранимая процедура будет использоваться в следующих примерах:

CREATE PROCEDURE AdoProcess_Test1
AS
BEGIN
    SET NOCOUNT ON     -- Используется для повышения производительности и с целью
            -- убедиться, что обратно не отправляется ненужная информация
    DECLARE @time VARCHAR(16)
    DECLARE @time VARCHAR(16)
    SET @time = CONVERT(VARCHAR(16),GETDATE(),114)
    RAISERROR( 'Completed 25%% At %s', 2, 1, @time) WITH NOWAIT
    WAITFOR DELAY '00:00:03'
    SET @time = CONVERT(VARCHAR(16),GETDATE(),114)
    RAISERROR( 'Completed 50%% At %s', 2, 2, @time) WITH NOWAIT
    WAITFOR DELAY '00:00:03'
    SET @time = CONVERT(VARCHAR(16),GETDATE(),114)
    RAISERROR( 'Completed 75%% At %s', 1, 3, @time) WITH NOWAIT
    WAITFOR DELAY '00:00:03'
    SET @time = CONVERT(VARCHAR(16),GETDATE(),114)
    RAISERROR( 'Completed 100%% At %s', 1, 4, @time) WITH NOWAIT
END;

Самыми важными строками являются те, которые начинаются с RAISERROR. Для этого примера мы жестко запрограммировали строки сообщений внутри хранимой процедуры. Обычной рекомендацией является добавление пользовательских сообщений в базу данных и ссылка на номер сообщения в RAISERROR, смотрите документацию MSDN. В строке сообщения используется такой же синтаксис, что и для функции C printf. Вот почему двойной символ %% присутствует в строке.

Формат строки RAISERROR такой:

RAISERROR( <Message/MessageId>, <Severity>, <State>[, <Arguments>]) [WITH <Options>]
  • Message/MessageId (сообщение/идентификатор сообщения) -  Реальное сообщение, которое будет возвращаться клиенту, можно использовать символы-заполнители printf для указания расположения переменных.
  • Severity (серьезность) сообщения – Меньше 10 для информационных сообщений.
  • State (Состояние) – Это уникальный номер, обозначающий, где в хранимой процедуре была возбуждена RAISERROR.
  • Arguments (Аргументы) – Необязательные аргументы для Сообщения, если используются символы-заполнители printf.
  • Options (Параметры) – Дополнительные параметры, в нашем случае мы хотим возвращать сообщение, как только оно было возбуждено, поэтому используется параметр NOWAIT. Вы можете отправлять сообщения в журнал регистрации событий, если нужно.

Пример имеет пару вспомогательных функций, которые подключаются к базе данных и создают/удаляют хранимую процедуру автоматически в tempdb. Поэтому вам необходимо разрешение (полномочия) CREATE/DROP PROCEDURE в tempdb.

Связывающая строка

Связывающая строка является одной из самых важных вещей во всей установке. Для данного примера мы жестко закодировали ее внутри класса C#, но обычно она помещается в файл конфигурации приложения или веб-приложения.

private const string ConnectionStr = "Data Source=(local);
    Initial Catalog=tempdb;Trusted_Connection=SSPI;Asynchronous Processing=true";

Полный список всех параметров, которые вы можете использовать при подключении к SQL, смотрите в документации MSDN. Описание используемых  нами параметров приводится ниже:

  • Источник данных – Это сервер, к которому вы собираетесь подключаться. Мы используем собственный локальный сервер. Если вы установили версию SQL Express с Visual Studio, то вам нужно изменить имя сервера с (локальный) на (локальный)\SQLEXPRESS.
  • Исходный каталог – Это имя реальной базы данных, размещающейся на сервере SQL, которую вы будете использовать. Если вы не имеете полномочий CREATE/DROP в tempdb, то измените значение параметра на имя той базы данных, в которой у вас есть эти полномочия.
  • Защищенное соединение – Этот параметр сообщает клиентской программе SQL, что вы используете ваши параметры доступа в Windows для возможностей технологии единого входа (Single Sign On). Рекомендуется использовать SSPI вместо значения истина.
  • Асинхронная обработка – Чтобы заставить ADO.NET выполнять асинхронную обработку (вызов методов Begin (начать) на командном объекте), этот параметр должен иметь значение trueили в противном случае вы получите InvalidOperationException в примере. (истина),

Для реальных приложений мы обычно добавляем параметры 'Имя приложения' и 'Идентификатор Workshare' в соединение. DBA знает, которое приложение/компьютер вызывает проблему в базе данных (поддерживает дружественность с DBA!).