При организации обмена данными между устаревшими системами на базе 1С 7.7 и современными конфигурациями на 1С 8.3 программисты часто используют механизм OLE (COM-соединение). Однако этот метод таит в себе множество нюансов, особенно когда речь заходит о реквизитах с типом Справочник (или другой объект) неопределенного вида. Рассмотрим подробнее, почему возникает ошибка при получении внутреннего идентификатора, и разберем по шагам, как правильно организовать загрузку в такой ситуации.
Разберем типичную ситуацию: в базе 1С 7.7 у документа есть реквизит, тип которого установлен как "Справочник" без указания конкретного вида (составной тип данных в терминах 7.7). При попытке получить внутреннее представление этого объекта через OLE-соединение в базе 1С 8 с помощью метода База.ЗначениеВСтрокуВнутр(Док.Организация), система возвращает некорректную строку.
Проанализируем пример:
7.7 код выдает: {"B","0","0","0","0","0"," 10601 5202 "}. Здесь число 10601 — это внутренний идентификатор метаданных (вида справочника).1С 8 тот же вызов возвращает: {"B","0","0","0","0","0"," 0 5202 "}.Как мы видим, на месте идентификатора вида справочника появляется "0". Это происходит из-за особенностей маршалинга (передачи данных между процессами). Когда 1С 8 обращается к объекту неопределенного типа в 7.7, COM-прослойка не может правильно передать контекст метаданных, и информация о том, к какому именно справочнику относится элемент, теряется. Остается только сам ID элемента, который без ссылки на вид справочника становится бесполезным.
Самый надежный способ решить проблему — заставить базу-источник (7.7) саму обработать объект и вернуть уже готовую строку. Для этого нам потребуется внести небольшое изменение в глобальный модуль базы 1С 7.7. Если политика компании позволяет редактировать конфигурацию, это лучший вариант.
Выясним причину успеха этого метода: выполнение кода происходит целиком внутри адресного пространства 1С 7.7, и данные передаются в 1С 8 уже в виде простого типа Строка, который OLE передает без искажений.
Добавьте в Глобальный модуль 1С 7.7 следующую функцию:
Функция глПолучитьВнутреннююСтроку(Объект) Экспорт
Возврат ЗначениеВСтрокуВнутр(Объект);
КонецФункции
Теперь в коде на стороне 1С 8.3 мы будем вызывать эту функцию вместо прямого обращения к методу ЗначениеВСтрокуВнутр:
// В базе 1С 8.3
Объект77 = База.CreateObject("Документ.Банк");
Объект77.ВыбратьДокументы(ДатаНач, ДатаКон);
Пока Объект77.ПолучитьДокумент() = 1 Цикл
// Вызываем нашу экспортную функцию из глобального модуля
ВнутрСтрока = База.глПолучитьВнутреннююСтроку(Объект77.Организация);
Сообщить("Получена корректная строка: " + ВнутрСтрока);
КонецЦикла;
Если изменять конфигурацию 7.7 категорически нельзя, проанализируем ситуацию с другой стороны. У любого объекта в 1С 7.7 (будь то справочник, документ или перечисление) есть встроенный метод Вид(), который возвращает строковое наименование типа метаданных.
Рассмотрим по шагам алгоритм получения данных:
Док.Организация.Вид().Пример реализации на стороне 1С 8:
ИмяВида = Док77.Организация.Вид(); // Например, вернет "Банки"
Если ЗначениеЗаполнено(ИмяВида) Тогда
СпрОбъект = База.CreateObject("Справочник." + ИмяВида);
// Теперь, когда объект типизирован, НайтиЭлемент сработает корректно
Если СпрОбъект.НайтиЭлемент(Док77.Организация) = 1 Тогда
ВнутрСтрока = База.ЗначениеВСтрокуВнутр(СпрОбъект.ТекущийЭлемент());
// Здесь строка будет содержать правильный ID вида
КонецЕсли;
КонецЕсли;
Важный нюанс: передача объекта в метод НайтиЭлемент через COM-соединение иногда может давать сбои. В этом случае лучше использовать поиск по коду или наименованию, если вы уверены в их уникальности.
Посмотрим на пример, предложенный участниками обсуждения. Если ваша задача — синхронизировать объекты (например, для заполнения регистра СоответствиеОбъектовИнформационныхБаз), можно уйти от использования внутренних строк в пользу бизнес-ключей.
Проанализируем код:
// Получаем данные напрямую через свойства OLE-объекта
КодОбъекта = Док77.Организация.Код;
НаименованиеОбъекта = Док77.Организация.Наименование;
// Далее ищем в базе 8 по этим полям или используем их для сопоставления
// Если нужно найти этот же объект в 7.7 для других манипуляций:
СпрТипа = База.CreateObject("Справочник.Банки");
Если СпрТипа.НайтиПоКоду(КодОбъекта) = 1 Тогда
// Объект найден
КонецЕсли;
Важно понимать: через OLE надежно передаются только простые типы: Число, Строка, Дата. Как только вы пытаетесь передать "ссылку" (объект Dispatch), вы становитесь зависимы от того, как COM-интерфейс интерпретирует этот объект в данный момент. Для стабильной работы всегда старайтесь преобразовывать данные в строку или число на стороне источника.
Если вы не хотите менять конфигурацию 7.7, можно попробовать использовать метод EvalExpr (ВычислитьВыражение). Этот метод выполняет строку кода внутри 1С 7.7. Однако у него есть существенное ограничение: он не видит локальные переменные вашего скрипта в 1С 8.
Чтобы этот метод сработал, объект нужно сначала "поместить" в глобальную область 7.7, например, в СписокЗначений, который можно передать как параметр, если в конфигурации есть глобальные переменные такого типа. Но на практике это оказывается сложнее, чем внедрение одной функции-обертки в глобальный модуль.
При работе с неопределенными видами справочников в 1С 7.7 через OLE:
ЗначениеВСтрокуВнутр(), вызванный напрямую из 1С 8, теряет идентификатор типа объекта.7.7 экспортную функцию, которая возвращает результат ЗначениеВСтрокуВнутр() в виде обычной строки..Вид(), а затем создать типизированный CreateObject для этого вида.Используя предложенные методы, вы сможете избежать ошибок при загрузке данных и обеспечить высокую точность сопоставления объектов между 1С 7.7 и 1С 8.3.