При интеграции 1С с внешней базой данных MySQL посредством ADO часто возникает необходимость не только считать строковые и числовые поля, но и извлечь двоичные данные — например, изображения, хранящиеся в полях типа BLOB или LONGBLOB.
В этой статье мы разберем, как правильно обходить объект ADODB.Recordset, выгружать полученную выборку в объект 1С ТаблицаЗначений и сохранять графические файлы на диск с помощью COM-объекта ADODB.Stream.
Проанализируем базовые сложности, с которыми сталкиваются разработчики при прямом подключении к MySQL из 1С:
ADODB.Recordset осуществляется через коллекцию RS.Fields("ИмяПоля").Value или по индексу колонки.COMSafeArray. Попытка записать его напрямую в файл или обработать стандартными функциями 1С без предварительного преобразования вызывает ошибку.CursorLocation = 2 / adUseServer), при вызове MoveNext() происходит регулярный сетевой обмен с СУБД. При наличии объёмных BLOB-полей это существенно замедляет выборку.Рассмотрим рабочее решение. Для эффективного сохранения каждого изображения создается отдельный поток ADODB.Stream, либо один поток циклически открывается, заполняется данными методом Write(), сохраняется в файл методом SaveToFile() и закрывается на каждой итерации выборки.
Разберем по шагам реализацию этого процесса:
ADODB.Command и ADODB.Recordset.CursorLocation = 3), чтобы вся выборка загружалась в память разом. Это ускорит обработку.ТаблицуЗначений в 1С, создавая колонки с именами, соответствующими полям MySQL.Пока НЕ RS.EOF Цикл считываем значение каждого поля. При обнаружении BLOB-поля с картинкой передаем COMSafeArray в объект ADODB.Stream и записываем файл на диск.Посмотрим на полный пример кода на языке 1С:
ТекстЗапроса = "select barcode, date_ins, date_upd, image from photo WHERE date_ins >= STR_TO_DATE('01.10.2017','%d.%m.%Y') AND date_ins <= STR_TO_DATE('06.10.2017','%d.%m.%Y')";
// Настраиваем команду ADO
Command = Новый COMОбъект("ADODB.Command");
Command.ActiveConnection = АДОСоединение;
Command.CommandText = ТекстЗапроса;
Command.CommandType = 1; // adCmdText
// Настраиваем набор записей
RS = Новый COMОбъект("ADODB.Recordset");
RS.ActiveConnection = АДОСоединение;
RS.CursorLocation = 3; // adUseClient (клиентский курсор ускоряет передачу данных)
RS.CursorType = 3; // adOpenStatic
// Выполняем запрос
RS = Command.Execute();
// Создаем ТаблицуЗначений для хранения результатов в 1С
РезультатЗапроса = Новый ТаблицаЗначений;
КоличествоПолей = RS.Fields.Count;
Для НомерКолонки = 0 По КоличествоПолей - 1 Цикл
РезультатЗапроса.Колонки.Добавить(RS.Fields.Item(НомерКолонки).Name);
КонецЦикла;
// Инициализируем Stream для сохранения двоичных файлов
StreamЗапись = Новый COMОбъект("ADODB.Stream");
StreamЗапись.Type = 1; // 1 = adTypeBinary
StreamЗапись.Mode = 3; // 3 = adModeReadWrite
// Обходим полученные записи
Пока НЕ RS.EOF Цикл
НоваяСтрока = РезультатЗапроса.Добавить();
Для НомерКолонки = 0 По КоличествоПолей - 1 Цикл
ИмяПоля = RS.Fields.Item(НомерКолонки).Name;
Значение = RS.Fields(ИмяПоля).Value;
Если ИмяПоля = "image" И Значение <> Неопределено Тогда
StreamЗапись.Open();
StreamЗапись.Write(Значение);
ИмяФайла = RS.Fields("barcode").Value;
ПутьКФайлу = КаталогВременныхФайлов() + ИмяФайла + ".jpg";
// 2 = adSaveCreateOverWrite (перезаписывать существующий файл)
StreamЗапись.SaveToFile(ПутьКФайлу, 2);
StreamЗапись.Close();
КонецЕсли;
НоваяСтрока[ИмяПоля] = Значение;
КонецЦикла;
RS.MoveNext();
КонецЦикла;
RS.Close();
Выясним причину возможных сбоев при эксплуатации подобного решения на серверных базах и различных операционных системах:
ADODB.Connection, ADODB.Recordset и ADODB.Stream являются технологиями Microsoft. На сервере 1С под управлением Linux данный код работать не будет.BLOB в объект ДвоичныеДанные.