Как получить результаты выборки и исходящие параметры хранимой процедуры через ADODB в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции 1С:Предприятия со сторонними базами данных Microsoft SQL Server с использованием технологии COM часто возникает задача вызова хранимой процедуры. Особую сложность вызывает сценарий, когда процедура должна одновременно возвращать как результирующий набор строк (Recordset через оператор SELECT), так и исходящие параметры (OUTPUT). Разберем, как правильно инициализировать параметры команды, выполнить вызов и корректно прочитать все возвращаемые данные.

Формирование вызова процедуры и передача параметров через ADODB.Command

Рассмотрим структуру вызова хранимой процедуры с использованием объекта ADODB.Command. Для корректной передачи параметров необходимо явно определить их тип и направление передачи с помощью метода CreateParameter, после чего добавить их в коллекцию Parameters.

Разберем пример создания подключения и выполнения хранимой процедуры, возвращающей выходной параметр:


COMОбъектSQL = Новый COMОбъект("ADODB.Connection");
COMОбъектSQL.ConnectionTimeOut = 30;
COMОбъектSQL.CommandTimeOut = 60;
COMОбъектSQL.ConnectionString = "Driver={SQL Server}; SERVER=MyServer; Database=MyBase; Uid=sa; Pwd=secret;";
COMОбъектSQL.Open();

Command = Новый COMОбъект("ADODB.Command");
Command.CommandTimeout = 100;
Command.ActiveConnection = COMОбъектSQL;
Command.CommandType = 4; // adCmdStoredProc (хранимая процедура)
Command.CommandText = "VladTest";

// Создание исходящего строкового параметра (adVarChar = 200, adParamOutput = 2, длина = 20)
Param = Command.CreateParameter("@p1", 200, 2, 20);
Command.Parameters.Append(Param);

// Выполнение команды без сохранения выборки
Command.Execute();

// Чтение значения возвращенного параметра
РезультатПараметра = Command.Parameters("@p1").Value;
Сообщить("Значение исходящего параметра: " + Строка(РезультатПараметра));

В этом примере процедура выполняется корректно, и значение параметра становится доступным в свойстве Value сразу после вызова метода Execute().

Причина блокировки значений исходящих параметров при чтении Recordset

Проанализируем ситуацию, когда хранимая процедура возвращает не только выходной параметр, но и выборку строк:


ALTER PROCEDURE [dbo].[VladTest]
    @p1 varchar(20) OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    SELECT @p1 = 'Результат параметра';
    SELECT 'Строка выборки 1' AS Поле1;
END

Если в коде 1С мы перехватываем результат выполнения в объект набора записей через RS = Command.Execute();, то попытка сразу прочитать значение Command.Parameters("@p1").Value вернет Неопределено или Null.

Выясним причину такого поведения. Согласно протоколу взаимодействия TDS (Tabular Data Stream) между клиентом OLE DB/ADO и MS SQL Server, сервер передает данные выходных параметров (OUTPUT) и код возврата (RETURN) в самом конце потока данных — строго после того, как переданы все строки всех результирующих наборов. Пока объект Recordset остается открытым и ассоциированным с активным соединением, ADO блокирует заполнение значений в коллекции Parameters.

Пошаговый алгоритм: получение выборки и исходящих параметров

Чтобы успешно получить и результирующий набор записей, и значения параметров OUTPUT, необходимо соблюдать строгую последовательность действий. Разберем по шагам правильный алгоритм:

  1. Настроить объект ADODB.Command, добавить все входные и выходные параметры через CreateParameter и метод Append.
  2. Выполнить команду и сохранить результат в переменную набора записей: RS = Command.Execute();.
  3. Обойти полученные строки в цикле и перенести данные во внутренние структуры 1С (например, в коллекцию ТаблицаЗначений или массив структур).
  4. Обязательно закрыть набор записей вызовом метода RS.Close();. Именно в этот момент ADO завершает чтение TDS-потока и наполняет значения выходных параметров.
  5. Прочитать значение требуемого исходящего параметра через Command.Parameters("@ИмяПараметра").Value.

Посмотрим на полный практический пример реализации этого алгоритма в коде 1С:


// 1. Инициализация команды
Command = Новый COMОбъект("ADODB.Command");
Command.CommandTimeout = 100;
Command.ActiveConnection = COMОбъектSQL;
Command.CommandType = 4; // adCmdStoredProc
Command.CommandText = "VladTest";

// Добавление выходного параметра
ParamOut = Command.CreateParameter("@p1", 200, 2, 20);
Command.Parameters.Append(ParamOut);

// 2. Выполнение и получение Recordset
RS = Command.Execute();

// 3. Обход строк набора данных
ТаблицаРезультатов = Новый ТаблицаЗначений;
ТаблицаРезультатов.Колонки.Добавить("Поле1");

Пока RS.EOF() = 0 Цикл
    НоваяСтрока = ТаблицаРезультатов.Добавить();
    НоваяСтрока.Поле1 = RS.Fields(0).Value;
    RS.MoveNext();
КонецЦикла;

// 4. Явное закрытие набора записей для освобождения потока данных
RS.Close();

// 5. Чтение исходящего параметра
ВыходноеЗначение = Command.Parameters("@p1").Value;
Сообщить("Прочитано из выборки строк: " + Строка(ТаблицаРезультатов.Количество()));
Сообщить("Прочитан выходной параметр: " + Строка(ВыходноеЗначение));

Особенности работы с курсорами и несколькими выборками

Рассмотрим дополнительные технические нюансы, с которыми можно столкнуться при использовании ADODB в 1С:

  1. Ошибка чтения свойства RecordCount: По умолчанию при вызове метода Execute() открывается однонаправленный серверный курсор (adOpenForwardOnly). У такого курсора свойство RecordCount возвращает -1 или вызывает ошибку. Для обхода данных следует использовать цикл Пока RS.EOF() = 0 Цикл либо предварительно переключить курсор на клиентский, установив свойство COMОбъектSQL.CursorLocation = 3 (adUseClient).
  2. Влияние директивы SET NOCOUNT ON: Если хранимая процедура выполняет операции модификации данных (INSERT, UPDATE, DELETE) и в ее начале не указана директива SET NOCOUNT ON, SQL Server отправляет служебные сообщения о количестве затронутых строк. ADO воспринимает их как промежуточные закрытые наборы записей, что может привести к пустой выборке. Если директиву изменить нельзя, необходимо перебирать наборы методом RS = RS.NextRecordset(); до получения основного набора строк.
  3. Параметр с индексом 0 (Return Value): Коллекция Parameters по умолчанию может резервировать нулевой элемент для возвращаемого значения процедуры (RETURN). При позиционном обращении по индексам (0, 1, 2) следует помнить, что пользовательские параметры могут начинаться с индекса 1, поэтому безопаснее обращаться к ним по именам: Command.Parameters("@p1").Value.

Ограничения платформы и альтернативные решения

Следует учитывать системные ограничения:

  1. Зависимость от операционной системы: Использование COMОбъект("ADODB.Command") возможно только на платформе под управлением Windows. Если сервер 1С работает под управлением Linux, вызов COM-объектов вызовет исключение.
  2. Разрядность драйверов: Для 64-разрядного сервера 1С:Предприятия требуются установленные 64-битные версии поставщиков OLE DB или драйверов ODBC.

В качестве кроссплатформенной альтернативы рекомендуется использовать механизм платформы «Внешние источники данных», который работает через ODBC-драйверы без прямого использования COM-объектов.

← На главную