Как загрузить документ из внешней базы-копии 1С 7.7 с возможностью подбора?

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

Задача переноса данных между базами 1С 7.7 встречается довольно часто. Особенно актуален сценарий, когда необходимо восстановить случайно удаленный документ из резервной копии базы. Казалось бы, если конфигурации идентичны, процесс должен быть простым. Однако при реализации механизма "подбора" документов из внешней базы через OLE-соединение или другими методами возникают технические нюансы.

В этой статье мы подробно разберем, как организовать подключение к внешней базе, эмулировать интерфейс подбора документа и корректно перенести данные, учитывая особенности ссылочных типов и идентификаторов объектов.

Основные подходы к решению задачи

Рассмотрим три основных способа реализации переноса документа из базы-копии в рабочую базу:

  1. OLE Automation (V77.Application): Классический метод подключения и программного чтения данных.
  2. Сериализация (ЗначениеВСтрокуВнутр): Метод, основанный на совпадении внутренних идентификаторов (UID) в копиях базы.
  3. Прямые запросы (1Cpp/ODBC): Наиболее быстрый метод для работы с большими объемами данных, требующий понимания структуры таблиц.

Разберем каждый из этих методов подробнее, уделив особое внимание проблеме "подбора" документа.

Метод 1: OLE Automation и эмуляция подбора

Многие разработчики сталкиваются с проблемой: при подключении по OLE невозможно открыть визуальную форму списка (журнала) документов удаленной базы в окне текущей базы. Метод ОткрытьФорму(), вызванный для OLE-объекта, либо отработает в фоновом режиме (пользователь ничего не увидит), либо вызовет ошибку.

Поэтому нам необходимо "эмулировать" подбор. Рассмотрим алгоритм действий:

  1. Подключаемся к базе-источнику через OLE.
  2. Программно получаем список документов (например, за определенный период) из источника.
  3. Загружаем основные реквизиты (Дата, Номер, Контрагент, Комментарий) в локальную ТаблицаЗначений.
  4. Показываем эту таблицу пользователю на форме обработки в текущей базе.
  5. Пользователь выбирает строку, и мы получаем ссылку на документ-источник для дальнейшей загрузки.

Пример кода подключения и получения списка документов:


// Создаем подключение
БазаОле = СоздатьОбъект("V77.Application");
Открыта = БазаОле.Initialize(БазаОле.RMTrade, "/D" + ПутьКБазе + " /N" + Пользователь + " /P" + Пароль, "NO_SPLASH_SHOW");

Если Открыта = 0 Тогда
    Предупреждение("Ошибка подключения!");
    Возврат;
КонецЕсли;

// Создаем объект документа в базе OLE
ОлеДок = БазаОле.CreateObject("Документ.Реализация");
ОлеДок.ВыбратьДокументы(НачДата, КонДата);

ТЗ = СоздатьОбъект("ТаблицаЗначений");
ТЗ.НоваяКолонка("ОлеОбъект"); // Здесь будем хранить саму OLE-ссылку (или ID)
ТЗ.НоваяКолонка("Представление");

Пока ОлеДок.ПолучитьДокумент() = 1 Цикл
    ТЗ.НоваяСтрока();
    // Сохраняем ссылку на объект OLE, чтобы потом к нему обратиться
    ТЗ.ОлеОбъект = ОлеДок.ТекущийДокумент(); 
    ТЗ.Представление = "№ " + ОлеДок.НомерДок + " от " + ОлеДок.ДатаДок;
КонецЦикла;

// Далее отображаем ТЗ на форме для выбора

Важный нюанс переноса реквизитов:

При переносе данных через OLE нельзя просто написать ДокПриемник.Контрагент = ДокИсточник.Контрагент. База-приемник не поймет OLE-объект. Нам необходимо найти соответствие.

Если базы идентичны (копии), то поиск лучше всего осуществлять по внутреннему идентификатору или коду. Если базы разные — по уникальным полям (ИНН, Код).

Метод 2: Использование внутренней сериализации (ЗначениеВСтрокуВнутр)

Если мы уверены, что вторая база — это точная копия первой (или была ею недавно), то внутренние идентификаторы (UID) объектов совпадают. Это открывает возможность для "ленивого" переноса ссылок.

Функции ЗначениеВСтрокуВнутр() и ЗначениеИзСтрокиВнутр() преобразуют объект 1С в строковое представление, содержащее тип объекта и его уникальный ID.

Проанализируем, как это работает:

  1. В базе-источнике мы берем документ и превращаем его в строку.
  2. Эту строку передаем в базу-приемник (через файл или текстовый параметр).
  3. В базе-приемнике восстанавливаем объект из строки.

Однако, здесь есть серьезное ограничение: ЗначениеИзСтрокиВнутр() в базе-приемнике создаст объект-ссылку. Если сам документ был удален в приемнике, вы получите ссылку вида <Объект не найден...>. Данные (реквизиты, табличная часть) при этом магическим образом не восстановятся. Этот метод идеален для поиска ссылки, но заполнять содержимое удаленного документа придется вручную, копируя реквизит за реквизитом.

Для передачи строки через OLE можно использовать экспортную функцию в глобальном модуле базы-источника:


// В Глобальном модуле базы-источника
Функция ПолучитьСтрВнутр(Объект) Экспорт
    Возврат ЗначениеВСтрокуВнутр(Объект);
КонецФункции

В базе-приемнике мы вызываем эту функцию:


СтрВнутр = БазаОле.EvalExpr("ПолучитьСтрВнутр(ОлеДок.ТекущийДокумент())");
СсылкаВНашейБазе = ЗначениеИзСтрокиВнутр(СтрВнутр);

Если СсылкаВНашейБазе.Выбран() = 0, значит документ в нашей базе удален окончательно, и нам нужно создавать новый (Новый()), а затем заполнять его данными из ОлеДок.

Метод 3: Прямые запросы и "типизация" (для продвинутых)

Использование прямых запросов (через компоненту 1Cpp или 1sqlite) позволяет обращаться к таблицам базы данных напрямую, минуя объектную модель 1С. Это работает намного быстрее OLE.

Особый интерес вызывает вопрос "типизации" данных из внешней базы. Когда мы делаем SQL-запрос к таблице внешней базы (например, через ATTACH DATABASE в SQLite), мы получаем поле ID в виде строки (обычно 9 или 13 символов).

Разберем пример получения данных из внешней базы с помощью ODBC и компоненты 1Cpp. Обратите внимание, как происходит подключение метаданных второй базы для правильной интерпретации имен таблиц.


Процедура Сформировать()
    рс = СоздатьОбъект("ODBCRecordSet");
    
    // Подготовка текста запроса
    // Используем синтаксис 1Cpp для обращения к таблицам
    ТекстЗапроса = "
    |SELECT
    |    Спр.DESCR as Наименование
    |    ,Спр.CODE as Код
    |    ,Спр.ID as [Ссылка :Справочник.Контрагенты] 
    |FROM dataBase2.dbo.@Справочник.Контрагенты Спр (nolock)
    |WHERE Спр.CODE = :ВыбКод
    |"; 
    
    // Обработка метаданных внешней базы
    глМД2 = СоздатьОбъект("MetaDataWork");
    ПутьКБазе2 = "D:\BackUp\CopyBase\";
    // Присоединяем MD-файл внешней базы для разрешения имен таблиц (@Справочник...)
    глМД2.ПрисоединитьМД(ПутьКБазе2 + "1Cv7.md");
    
    // Транслируем запрос (заменяем @Имя на реальные имена таблиц SQL/DBF)
    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "@", "$");
    ТекстЗапроса = глМД2.ОбрМетаСКЛ(ТекстЗапроса);
    
    // Выполнение
    ТЗ = рс.ВыполнитьИнструкцию(ТекстЗапроса);
    ТЗ.ВыбратьСтроку();
КонецПроцедуры

Что такое типизация в данном контексте?

В строке запросе Спр.ID as [Ссылка :Справочник.Контрагенты] мы явно указываем компоненте 1Cpp, что полученный ID нужно превратить в объект справочника текущей базы. Это сработает корректно только если ID объекта во внешней базе и в текущей базе совпадают. В случае баз-копий это условие выполняется.

Рекурсивная обработка ссылочных типов

При любом методе переноса (кроме полного восстановления XML/URBD) мы сталкиваемся с необходимостью копирования значений реквизитов. Простые типы (Число, Строка, Дата) переносятся напрямую. Ссылочные типы (Справочники, Документы, Перечисления) требуют особого подхода.

Посмотрим на алгоритм универсальной функции конвертации:

  1. Определяем тип значения реквизита в базе-источнике.
  2. Если это Перечисление: Получаем его идентификатор (строку) в источнике и ищем такой же идентификатор в метаданных приемника. Нельзя переносить перечисления как OLE-объекты.
  3. Если это Справочник: Ищем элемент в приемнике. Поиск можно вести по ЗначениеВСтрокуВнутр (если базы идентичны) или по Коду/Наименованию. Если элемент не найден — его нужно создать (рекурсивно вызвать функцию переноса для этого элемента).
  4. Если это Документ: Аналогично справочнику.

Рекомендации по безопасности данных

При реализации переноса документа из внешней базы обязательно учитывайте следующие моменты:

Для разовых задач восстановления данных, если программирование кажется избыточным, можно воспользоваться стандартной обработкой MCExp.ert (Выгрузка и загрузка данных в формате XML), которая часто входит в комплект конфигураций или находится на дисках ИТС. Она корректно обрабатывает структуру метаданных и переносит объекты вместе с их ссылочным окружением.

← На главную