При интеграции 1С с внешними базами данных через COM-объект ADODB.Connection часто возникает задача получения данных в виде привычной для разработчика коллекции — объекта ТаблицаЗначений. Если таблица-источник содержит десятки колонок, ручное их описание в коде становится трудоемким процессом. Разберем по шагам, как быстро и правильно преобразовать выборку ADODB.Recordset в таблицу значений, как автоматизировать создание структуры колонок и какие нюансы производительности и совместимости необходимо учитывать.
Рассмотрим универсальное решение, которое считывает коллекцию Fields объекта ADODB.Recordset, автоматически добавляет нужные колонки с базовой типизацией и построчно заполняет строки таблицы.
Посмотрим на программный код реализации такой функции:
Функция ВыгрузитьРекордсетВТаблицуЗначений(НаборЗаписейADO) Экспорт
ТаблицаРезультат = Новый ТаблицаЗначений;
Если НаборЗаписейADO = Неопределено Тогда
Возврат ТаблицаРезультат;
КонецЕсли;
КоличествоКолонок = НаборЗаписейADO.Fields.Count;
Если КоличествоКолонок = 0 Тогда
Возврат ТаблицаРезультат;
КонецЕсли;
// Шаг 1. Формирование структуры колонок
Для ИндексКолонки = 0 По КоличествоКолонок - 1 Цикл
ПолеADO = НаборЗаписейADO.Fields.Item(ИндексКолонки);
ИмяКолонки = ПолеADO.Name;
// Корректируем имя колонки под требования идентификаторов 1С
ИмяКолонки1С = СтрЗаменить(ИмяКолонки, " ", "_");
ИмяКолонки1С = СтрЗаменить(ИмяКолонки1С, "-", "_");
// Определение базовых типов (3 - adInteger, 5 - adDouble, 131 - adNumeric)
ТипADO = ПолеADO.Type;
Если ТипADO = 3 Или ТипADO = 5 Или ТипADO = 131 Тогда
ТаблицаРезультат.Колонки.Добавить(ИмяКолонки1С, Новый ОписаниеТипов("Число"), ИмяКолонки);
ИначеЕсли ТипADO = 135 Или ТипADO = 7 Тогда // adDBTimeStamp, adDate
ТаблицаРезультат.Колонки.Добавить(ИмяКолонки1С, Новый ОписаниеТипов("Дата"), ИмяКолонки);
Иначе
ТаблицаРезультат.Колонки.Добавить(ИмяКолонки1С, , ИмяКолонки);
КонецЕсли;
КонецЦикла;
// Шаг 2. Заполнение строк данными
Пока НаборЗаписейADO.EOF = 0 Цикл
НоваяСтрока = ТаблицаРезультат.Добавить();
Для ИндексКолонки = 0 По КоличествоКолонок - 1 Цикл
Попытка
Значение = НаборЗаписейADO.Fields(ИндексКолонки).Value;
НоваяСтрока[ИндексКолонки] = Значение;
Исключение
НоваяСтрока[ИндексКолонки] = Неопределено;
КонецПопытки;
КонецЦикла;
НаборЗаписейADO.MoveNext();
КонецЦикла;
Возврат ТаблицаРезультат;
КонецФункции
Построчный обход COM-объекта через метод MoveNext() может работать медленно на больших объемах (десятки и сотни тысяч записей) из-за постоянных межпроцессных вызовов между средой 1С и библиотекой ADO. Чтобы многократно ускорить операцию, применим метод GetRows().
Метод GetRows() возвращает все строки набора в виде двумерного COM-массива (SafeArray). Обход такого массива во встроенном языке 1С выполняется значительно быстрее, чем поочередное переключение строк в рекордсете.
Разберем важную особенность: полученный массив является транспонированным. Первое измерение соответствует номеру колонки, а второе — номеру строки.
Функция ВыгрузитьРекордсетЧерезGetRows(НаборЗаписейADO) Экспорт
ТаблицаРезультат = Новый ТаблицаЗначений;
Если НаборЗаписейADO.EOF = 1 Тогда
Возврат ТаблицаРезультат;
КонецЕсли;
КоличествоКолонок = НаборЗаписейADO.Fields.Count;
Для Индекс = 0 По КоличествоКолонок - 1 Цикл
ТаблицаРезультат.Колонки.Добавить("Колонка_" + Индекс);
КонецЦикла;
// Получаем сразу все данные в двумерный массив
МассивДанных = НаборЗаписейADO.GetRows();
// Определяем границы SafeArray в 1С
КоличествоПолей = МассивДанных.ВГраница(1);
КоличествоЗаписей = МассивДанных.ВГраница(2);
Для НомерСтроки = 0 По КоличествоЗаписей Цикл
СтрокаТЗ = ТаблицаРезультат.Добавить();
Для НомерКолонки = 0 По КоличествоПолей Цикл
СтрокаТЗ[НомерКолонки] = МассивДанных[НомерКолонки, НомерСтроки];
КонецЦикла;
КонецЦикла;
Возврат ТаблицаРезультат;
КонецФункции
Еще один высокопроизводительный вариант исключения построчного COM-обращения — сохранение рекордсета в поток XML. Полученный XML-текст считывается стандартным объектом ЧтениеXML, после чего данные быстро переносятся в структуру 1С без обращения к ячейкам COM-объекта.
Если требуется регулярное взаимодействие со сторонней СУБД, проанализируем отказ от прямого использования устаревшего механизма ADODB в пользу встроенного функционала платформы 1С.
Запрос:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Договоры.НомерДоговора КАК НомерДоговора,
| Договоры.ДатаДоговора КАК ДатаДоговора,
| Договоры.Сумма КАК Сумма
|ИЗ
| ВнешнийИсточникДанных.ВнешняяБазаSQL.Таблица.dogovor КАК Договоры";
ТаблицаЗначений = Запрос.Выполнить().Выгрузить();
При работе с внешними выборками через ADODB следует помнить о следующих системных требованиях:
COMОбъект("ADODB.Connection") и COMОбъект("ADODB.Command") работают исключительно под управлением ОС Windows. Если сервер 1С функционирует на базе Linux, попытка создания такого COM-объекта завершится аварийной ошибкой.ТаблицаЗначений.Колонки.Добавить() требует корректный программный идентификатор, поэтому имена полей следует предварительно проверять и очищать.NULL: Не заполненные значения в SQL возвращаются в виде COM-типа NULL. При строгой типизации колонок таблицы значений это может приводить к ошибкам присвоения, поэтому рекомендуется проверять результирующие значения перед записью в строку.