При интеграции 1С с внешними базами данных, такими как Oracle, через механизм ВнешниеИсточникиДанных, мы часто сталкиваемся с нетривиальным поведением драйверов и платформы. Одной из самых загадочных и неприятных проблем является ситуация, когда при попытке прочитать таблицу, содержащую и текстовые описания, и двоичные данные (файлы, сканы, BLOB), кириллические строки превращаются в знаки вопроса («??????»), в то время как латиница и цифры отображаются корректно.
В этой статье мы подробно разберем, почему возникает эта ошибка, проанализируем поведение ODBC-драйверов и рассмотрим несколько способов решения задачи — от изменения текста запроса до архитектурного разделения данных.
Давайте смоделируем ситуацию. У нас есть внешняя база данных Oracle, в которой хранится таблица с документами. Структура таблицы включает:
NVARCHAR2).BLOB или LONG RAW).Мы настраиваем внешний источник данных в 1С, создаем форму списка и форму объекта. В форме списка (динамический список) все отображается корректно: мы видим русские названия продукции. Однако, стоит нам попытаться получить данные программно через запрос или открыть форму объекта, где выбираются все поля, как поле «Наименование» превращается в набор вопросительных знаков.
Если мы исключим из выборки поле с двоичными данными, строки снова начинают отображаться нормально. Это указывает на то, что проблема кроется не в глобальной настройке кодировки базы, а именно в механизме выборки смешанных типов данных.
Прежде чем переходить к лечению, давайте поставим диагноз. Существует несколько технических причин такого поведения:
NLS_LANG должна точно соответствовать кодировке данных в базе.Рассмотрим способы решения этой проблемы, от простых к более сложным и надежным.
Наиболее надежным решением, к которому приходят опытные разработчики, является отказ от выборки двоичных данных в одном запросе с описательными полями. Двоичные данные — это «тяжелый» контент, который редко нужен пользователю непосредственно при просмотре карточки или списка. Обычно файл нужен только в момент скачивания или сохранения на диск.
Давайте реализуем подход, при котором мы не тянем ДвоичныеДанные в основную форму, а получаем их отдельным запросом только по требованию.
Шаг 1. Настройка внешнего источника
В дереве метаданных во внешнем источнике данных лучше иметь две сущности (даже если физически это одна таблица, можно добавить ее дважды с разными именами или использовать View на стороне Oracle):
ТаблицаДокументы — содержит все поля кроме двоичных данных.ТаблицаКонтент — содержит только ID и поле с двоичными данными.Шаг 2. Реализация скачивания файла
На форме объекта мы отображаем только строковые данные. Для работы с файлом добавляем команду «Сохранить файл». В обработчике этой команды мы выполняем отдельный запрос к источнику, выбирая данные по ID.
Пример программного кода для получения данных:
&НаСервере
Функция ПолучитьФайлИзOracle(ИдентификаторФайла)
Запрос = Новый Запрос;
// Обращаемся к таблице, где мы намеренно оставили двоичные данные
// или используем ту же таблицу, но выбираем ТОЛЬКО двоичные данные
Запрос.Текст =
"ВЫБРАТЬ
| ДанныеИзОракла.Данные_документа КАК ДвоичныеДанные
|ИЗ
| ВнешнийИсточникДанных.ВнешняяБаза.Таблица.Документы_Интегрослоя КАК ДанныеИзОракла
|ГДЕ
| ДанныеИзОракла.ID = &ID";
Запрос.УстановитьПараметр("ID", ИдентификаторФайла);
Результат = Запрос.Выполнить();
Если Не Результат.Пустой() Тогда
Выборка = Результат.Выбрать();
Выборка.Следующий();
Возврат Выборка.ДвоичныеДанные;
КонецЕсли;
Возврат Неопределено;
КонецФункции
Такой подход решает сразу две проблемы: устраняет ошибку кодировки (так как типы не смешиваются) и оптимизирует производительность (мы не гоняем по сети тяжелые файлы при простом открытии формы).
Если разделение данных невозможно и вам необходимо получить все данные одним запросом, попробуйте изменить порядок полей. Это специфическая особенность работы драйверов ODBC с LOB-типами.
Давайте посмотрим на "проблемный" запрос:
ВЫБРАТЬ ПЕРВЫЕ 1
ДанныеИзОракла.Данные_документа КАК Ссылка, // Двоичные данные идут первыми
ДанныеИзОракла.Наименование_продукции КАК Наименование_продукции
ИЗ
ВнешнийИсточникДанных.ВнешняяБаза.Таблица.Документы_Интегрослоя КАК ДанныеИзОракла
В этом случае буфер чтения заполняется большим объемом данных первого поля, и на чтении второго поля драйвер "сбивается", выдавая вопросительные знаки. Попробуем переписать запрос так, чтобы ДвоичныеДанные всегда были в самом конце списка выборки SELECT.
ВЫБРАТЬ ПЕРВЫЕ 1
ДанныеИзОракла.Наименование_продукции КАК Наименование_продукции, // Сначала строки
ДанныеИзОракла.Данные_документа КАК Ссылка // Двоичные данные в конце
ИЗ
ВнешнийИсточникДанных.ВнешняяБаза.Таблица.Документы_Интегрослоя КАК ДанныеИзОракла
Во многих случаях, особенно при прямом использовании ODBC, это простое действие восстанавливает нормальное отображение кириллицы.
Если вы имеете доступ к администрированию базы данных Oracle, наиболее "чистым" вариантом будет создание специального представления (View) для 1С.
Вместо того чтобы заставлять 1С мучиться с "сырой" таблицей, создайте View, которое:
Затем в 1С вы подключаете это представление как таблицу внешнего источника. А для получения самого файла используете прямую таблицу, обращаясь к ней точечно по ID, как описано в Способе 1. Это позволит избежать создания дублей данных и обеспечит стабильную работу интерфейса 1С.
Иногда проблема кроется не в самом запросе, а в настройках соединения. Давайте проверим настройки драйвера ODBC и системные переменные на сервере, где работает служба 1С.
1. Переменная NLS_LANG
Убедитесь, что в системных переменных окружения (Environment Variables) задана переменная NLS_LANG. Она сообщает клиенту Oracle (которым является сервер 1С), в какой кодировке ожидать данные. Для России значение часто выглядит как:
RUSSIAN_CIS.CL8MSWIN1251 (для Windows-кодировки)AMERICAN_AMERICA.AL32UTF8 (если база в Unicode)Важно: после изменения переменной службу сервера 1С необходимо перезапустить.
2. Настройки DSN (Data Source Name)
В настройках источника ODBC для драйвера Oracle обратите внимание на вкладку Workarounds или Options. Следующие параметры могут помочь:
Проблема "Двоичные данные ломают строки" — классический пример конфликта на уровне драйверов баз данных при работе через прослойку внешних источников. Хотя манипуляции с порядком полей и настройками драйвера могут помочь, мы рекомендуем использовать архитектурный подход:
Разделяйте данные. Не выводите поля типа ДвоичныеДанные в списки и формы по умолчанию. Загружайте тяжелые данные только в тот момент, когда они действительно нужны пользователю (нажатие кнопки «Скачать» или «Сохранить»), используя для этого отдельный точечный запрос.