Как загрузить данные из 1С 7.7 в 8 через OLE, если реквизит имеет тип Справочник неопределенного вида?

Программист 1С v7.7 1C:Бухгалтерия IT и автоматизация бизнеса
← На главную

При организации обмена данными между устаревшими системами на базе 1С 7.7 и современными конфигурациями на 1С 8.3 программисты часто используют механизм OLE (COM-соединение). Однако этот метод таит в себе множество нюансов, особенно когда речь заходит о реквизитах с типом Справочник (или другой объект) неопределенного вида. Рассмотрим подробнее, почему возникает ошибка при получении внутреннего идентификатора, и разберем по шагам, как правильно организовать загрузку в такой ситуации.

В чем заключается проблема?

Разберем типичную ситуацию: в базе 1С 7.7 у документа есть реквизит, тип которого установлен как "Справочник" без указания конкретного вида (составной тип данных в терминах 7.7). При попытке получить внутреннее представление этого объекта через OLE-соединение в базе 1С 8 с помощью метода База.ЗначениеВСтрокуВнутр(Док.Организация), система возвращает некорректную строку.

Проанализируем пример:

  1. В родной среде 7.7 код выдает: {"B","0","0","0","0","0"," 10601 5202 "}. Здесь число 10601 — это внутренний идентификатор метаданных (вида справочника).
  2. При обращении через OLE из 1С 8 тот же вызов возвращает: {"B","0","0","0","0","0"," 0 5202 "}.

Как мы видим, на месте идентификатора вида справочника появляется "0". Это происходит из-за особенностей маршалинга (передачи данных между процессами). Когда 1С 8 обращается к объекту неопределенного типа в 7.7, COM-прослойка не может правильно передать контекст метаданных, и информация о том, к какому именно справочнику относится элемент, теряется. Остается только сам ID элемента, который без ссылки на вид справочника становится бесполезным.

Решение №1: Создание функции-обертки в 1С 7.7 (рекомендуемое)

Самый надежный способ решить проблему — заставить базу-источник (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.Организация);
    Сообщить("Получена корректная строка: " + ВнутрСтрока);
КонецЦикла;

Решение №2: Использование метода Вид() и создание типизированного объекта

Если изменять конфигурацию 7.7 категорически нельзя, проанализируем ситуацию с другой стороны. У любого объекта в 1С 7.7 (будь то справочник, документ или перечисление) есть встроенный метод Вид(), который возвращает строковое наименование типа метаданных.

Рассмотрим по шагам алгоритм получения данных:

  1. Получаем строковое название вида справочника через Док.Организация.Вид().
  2. Создаем в OLE-сессии объект конкретного справочника.
  3. Ищем элемент в этом объекте.

Пример реализации на стороне 1С 8:


ИмяВида = Док77.Организация.Вид(); // Например, вернет "Банки"
Если ЗначениеЗаполнено(ИмяВида) Тогда
    СпрОбъект = База.CreateObject("Справочник." + ИмяВида);
    // Теперь, когда объект типизирован, НайтиЭлемент сработает корректно
    Если СпрОбъект.НайтиЭлемент(Док77.Организация) = 1 Тогда
        ВнутрСтрока = База.ЗначениеВСтрокуВнутр(СпрОбъект.ТекущийЭлемент());
        // Здесь строка будет содержать правильный ID вида
    КонецЕсли;
КонецЕсли;

Важный нюанс: передача объекта в метод НайтиЭлемент через COM-соединение иногда может давать сбои. В этом случае лучше использовать поиск по коду или наименованию, если вы уверены в их уникальности.

Решение №3: Поиск по уникальным реквизитам

Посмотрим на пример, предложенный участниками обсуждения. Если ваша задача — синхронизировать объекты (например, для заполнения регистра СоответствиеОбъектовИнформационныхБаз), можно уйти от использования внутренних строк в пользу бизнес-ключей.

Проанализируем код:


// Получаем данные напрямую через свойства OLE-объекта
КодОбъекта = Док77.Организация.Код;
НаименованиеОбъекта = Док77.Организация.Наименование;

// Далее ищем в базе 8 по этим полям или используем их для сопоставления
// Если нужно найти этот же объект в 7.7 для других манипуляций:
СпрТипа = База.CreateObject("Справочник.Банки");
Если СпрТипа.НайтиПоКоду(КодОбъекта) = 1 Тогда
    // Объект найден
КонецЕсли;

Важно понимать: через OLE надежно передаются только простые типы: Число, Строка, Дата. Как только вы пытаетесь передать "ссылку" (объект Dispatch), вы становитесь зависимы от того, как COM-интерфейс интерпретирует этот объект в данный момент. Для стабильной работы всегда старайтесь преобразовывать данные в строку или число на стороне источника.

Использование EvalExpr для обхода ограничений

Если вы не хотите менять конфигурацию 7.7, можно попробовать использовать метод EvalExpr (ВычислитьВыражение). Этот метод выполняет строку кода внутри 1С 7.7. Однако у него есть существенное ограничение: он не видит локальные переменные вашего скрипта в 1С 8.

Чтобы этот метод сработал, объект нужно сначала "поместить" в глобальную область 7.7, например, в СписокЗначений, который можно передать как параметр, если в конфигурации есть глобальные переменные такого типа. Но на практике это оказывается сложнее, чем внедрение одной функции-обертки в глобальный модуль.

Подведем итоги

При работе с неопределенными видами справочников в 1С 7.7 через OLE:

Используя предложенные методы, вы сможете избежать ошибок при загрузке данных и обеспечить высокую точность сопоставления объектов между 1С 7.7 и 1С 8.3.

← На главную