При интеграции 1С со сторонними базами данных на платформе MS SQL Server разработчики часто используют прямое подключение через COM-объект ADODB.Connection. В большинстве случаев числа, даты и короткие строки считываются без нареканий. Однако при попытке прочитать определенные текстовые поля (комментарии, описания задач, длинные примечания) вместо читаемого текста на кириллице в 1С возвращается набор нечитаемых знаков или знаков вопроса, хотя в SQL Server Management Studio (SSMS) этот же запрос отображает данные корректно.
Разберем детально, почему возникает эта ошибка и какими способами можно получить корректные строковые данные в 1С.
Проанализируем механизм передачи строковых данных из MS SQL в среду 1С:Предприятие. Основная причина сбоя заключается в том, как драйверы доступа к данным и COM-модель ADO работают с большими неструктурированными полями (LOB — Large Object):
text, ntext, varchar(max) и nvarchar(max): В объектной модели ADODB поля неограниченной длины распознаются как потоковые типы данных (adLongVarChar или adLongVarWChar). При прямом обращении через свойство Поле.Value механизм COM-маршалинга между ADO и платформой 1С не всегда может корректно преобразовать указатель на поток в стандартную Unicode-строку (BSTR). В результате байты считываются со смещением или неверной интерпретацией длины, что приводит к искажению символов.DRIVER={SQL Server Native Client 11.0}, взаимодействие происходит через промежуточный мост (MSDASQL к ODBC), который исторически испытывает трудности при передаче полей с модификатором MAX напрямую в COM-свойства.Рассмотрим самое простое и эффективное решение проблемы, не требующее изменения конфигурации драйверов на сервере. Если максимальная длина текста в поле заведомо не превышает 4000 символов, приведем поле к фиксированному типу Юникод-строки nvarchar(4000) прямо в тексте запроса или в представлении (View) на стороне SQL Server.
Посмотрим на пример формирования SQL-запроса в коде 1С:
Соединение = Новый COMОбъект("ADODB.Connection");
Соединение.ConnectionString = "DRIVER={SQL Server Native Client 11.0};SERVER=" + Объект.Сервер + ";UID=" + Объект.Пользователь + ";PWD=" + Объект.Пароль + ";DATABASE=" + Объект.База + ";";
Соединение.Open();
Команда = Новый COMОбъект("ADODB.Command");
Команда.ActiveConnection = Соединение;
// Приводим поле Comments типа varchar(max)/text к nvarchar(4000)
Команда.CommandText =
"SELECT
| ID,
| CAST(Comments AS nvarchar(4000)) AS TaskComments
|FROM dbo.Tasks";
Выборка = Команда.Execute();
Пока Выборка.EOF() = 0 Цикл
ТекстКомментария = Выборка.Fields("TaskComments").Value;
Сообщить("Комментарий: " + ТекстКомментария);
Выборка.MoveNext();
КонецЦикла;
Выборка.Close();
Соединение.Close();
Важное ограничение: Тип nvarchar(4000) вмещает до 4 000 символов. Если исходный текст в базе данных длиннее, SQL Server выполнит неявное усечение (обрезку) строки без вывода ошибки. Если критично получать тексты большего объема, рассмотрим альтернативные варианты.
Разберем изменение параметров подключения. Отказ от ODBC-драйвера в пользу прямого OLE DB провайдера позволяет избавиться от промежуточных уровней трансляции и корректно передавать длинные Unicode-поля в COM-интерфейс 1С.
Посмотрим, как изменить строку подключения:
// Вариант 1: Использование SQL Server Native Client OLE DB Provider
СтрокаПодключения = "Provider=SQLNCLI11;Server=" + Объект.Сервер + ";Database=" + Объект.База + ";Uid=" + Объект.Пользователь + ";Pwd=" + Объект.Пароль + ";DataTypeCompatibility=80;";
// Вариант 2: Использование современного Microsoft OLE DB Driver for SQL Server (MSOLEDBSQL)
// СтрокаПодключения = "Provider=MSOLEDBSQL;Server=" + Объект.Сервер + ";Database=" + Объект.База + ";UID=" + Объект.Пользователь + ";PWD=" + Объект.Пароль + ";";
Соединение = Новый COMОбъект("ADODB.Connection");
Соединение.ConnectionString = СтрокаПодключения;
Соединение.Open();
Параметр DataTypeCompatibility=80 сообщает провайдеру о необходимости приведения новых типов данных (включая varchar(max)) к классическим форматам, которые без сбоев воспринимаются стандартными COM-библиотеками.
Если в базе хранятся большие блоки текста неограниченного размера и мы не можем использовать CAST с фиксированной длиной, прочитаем значение поля по частям с помощью встроенного метода ADO GetChunk.
Рассмотрим пример чтения длинного текста порциями:
Функция ПрочитатьДлинныйТекстИзПоля(ПолеADO, РазмерБуфера = 4000)
ПолныйТекст = "";
ОбщийРазмер = ПолеADO.ActualSize;
Если ОбщийРазмер = 0 Тогда
Возврат "";
КонецЕсли;
СчитаноБайт = 0;
Пока СчитаноБайт < ОбщийРазмер Цикл
КусокТекста = ПолеADO.GetChunk(РазмерБуфера);
Если КусокТекста = Неопределено Тогда
Прервать;
КонецЕсли;
ПолныйТекст = ПолныйТекст + Строка(КусокТекста);
СчитаноБайт = СчитаноБайт + РазмерБуфера;
КонецЦикла;
Возврат ПолныйТекст;
КонецФункции
Проанализируем современный штатный подход платформы 1С:Предприятие 8.3. Вместо ручной работы с COM-объектами ADODB.Connection и ADODB.Recordset рекомендуется использовать объект метаданных Внешние источники данных:
varchar(max) и nvarchar(max) с типом Строка неограниченной длины.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Задачи.ID КАК ID,
| Задачи.Comments КАК Comments
|ИЗ
| ВнешнийИсточникДанных.ВнешняяБаза.Таблица.dbo_Tasks КАК Задачи";
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("Комментарий: " + Выборка.Comments);
КонецЦикла;
Использование внешних источников данных полностью исключает влияние COM-маршалинга и гарантирует корректное отображение любых текстовых полей вне зависимости от настроек драйвера.