Как в 1С 7.7 программно перебрать объекты, зарегистрированные для обмена УРБД?

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

При организации обмена между 1С 7.7 и 1С 8 часто возникает необходимость перехватывать только те данные, которые были изменены пользователями, без формирования стандартных файлов переноса УРБД. В платформе 1С 7.7 нет встроенного менеджера планов обмена, как в 1С 8, однако механизм распределенных информационных баз (УРБД) фиксирует все изменения в системной таблице _1SUPDTS. Разберем, как устроен этот механизм и как программно извлечь измененные объекты с помощью прямых запросов или штатных средств.

Структура таблицы регистрации изменений _1SUPDTS

Рассмотрим назначение основных полей системной таблицы _1SUPDTS (в файловом режиме — 1SUPDTS.DBF), в которую платформа записывает события модификации данных:

  1. DBSIGN — строковый идентификатор узла-получателя (периферийной базы).
  2. TYPEID — внутренний числовой идентификатор метаданных (соответствует ID вида объекта из файла описания структуры метаданных).
  3. OBJID — внутренний идентификатор конкретного объекта базы данных в 36-ричной системе счисления (Base36).
  4. DWNLDID — идентификатор пакета выгрузки. Если объект был изменен, но еще не включен в сессию обмена, поле содержит пустую строку.

Инициализация соответствий метаданных и чтение изменений через 1С++

Проанализируем практический подход с использованием внешней компоненты 1С++ и прямого доступа через объект ODBCRecordset. Чтобы сопоставить числовые TYPEID с понятными именами объектов метаданных, сформируем служебную таблицу соответствий и выполним выборку зарегистрированных объектов.

Посмотрим на пример заполнения таблицы соответствий метаданных:


Процедура ИнициализацияСоответствийОбъектов() Экспорт
    рс = СоздатьОбъект("ODBCRecordset");
    
    текстУдаления = "
    |IF EXISTS(SELECT name FROM sysobjects WHERE name = 'СоответствияОбъектов' AND xtype='U')
    |DROP TABLE [СоответствияОбъектов]
    |";
    рс.ВыполнитьСкалярный(текстУдаления);
    
    текстСоздания = "
    |CREATE TABLE [СоответствияОбъектов] (
    |    [ROW_ID] [int] IDENTITY (1, 1) NOT NULL,
    |    [ТипОбъекта] [numeric](5, 0) NOT NULL,
    |    [ТипОбъектаСтр] [char](35) COLLATE Cyrillic_General_CI_AS NOT NULL,
    |    [ВидОбъектаСтр] [char](45) COLLATE Cyrillic_General_CI_AS NOT NULL,
    |    [ИмяТаблицы] [char](10) COLLATE Cyrillic_General_CI_AS NOT NULL,
    |    CONSTRAINT [СоответствияОбъектов_PK] PRIMARY KEY CLUSTERED ([ROW_ID]) ON [PRIMARY]
    |) ON [PRIMARY]
    |";
    рс.ВыполнитьСкалярный(текстСоздания);
    
    ТекстДобавления = "
    |INSERT INTO СоответствияОбъектов (ТипОбъекта, ТипОбъектаСтр, ВидОбъектаСтр, ИмяТаблицы)
    |VALUES (:ТипОбъекта, :ТипОбъектаСтр, :ВидОбъектаСтр, ' ')
    |";
    
    Для сч = 1 По Метаданные.Документ() Цикл
        ИдентСтр = Метаданные.Документ(сч).Идентификатор;
        Идент = глMDW.ИДДокумента(сч);
        рс.УстановитьТекстовыйПараметр("ТипОбъекта", Идент);
        рс.УстановитьТекстовыйПараметр("ТипОбъектаСтр", "Документ");
        рс.УстановитьТекстовыйПараметр("ВидОбъектаСтр", ИдентСтр);
        рс.ВыполнитьСкалярный(ТекстДобавления);
    КонецЦикла;
    
    Для сч = 1 По Метаданные.Справочник() Цикл
        ИдентСтр = Метаданные.Справочник(сч).Идентификатор;
        Идент = глMDW.ИДСправочника(сч);
        рс.УстановитьТекстовыйПараметр("ТипОбъекта", Идент);
        рс.УстановитьТекстовыйПараметр("ТипОбъектаСтр", "Справочник");
        рс.УстановитьТекстовыйПараметр("ВидОбъектаСтр", ИдентСтр);
        рс.ВыполнитьСкалярный(ТекстДобавления);
    КонецЦикла;
КонецПроцедуры

Формирование пакета изменений и квитирование

Разберем цикл работы с изменениями: подготовку пакета, выборку измененных ссылок и последующее подтверждение (удаление переданных записей из _1SUPDTS).

1. Фиксируем номер нового пакета и помечаем им накопившиеся изменения:


Функция ПодготовитьКВыгрузке(ИдБазы = "1C8") Экспорт
    ТекстЗапроса = "
    |SET NOCOUNT ON;
    |DECLARE @NewId Char(9);
    |DECLARE @DBSign Char(9);
    |SET @DBSign = :ИдБазы;
    |SET @NewId = (SELECT LTRIM(dbo.convert10to36long(MAX(dbo.convert36to10(LEFT(dwnldid, 6))) + 1) + 'CB ') FROM _1sdwnlds WHERE direct = 'O');
    |
    |INSERT INTO [_1SDWNLDS] ([DWNLDID], [DBSIGN], [DIRECT], [ACKNOWL])
    |VALUES (@NewId, @DBSign, 'O', ' ');
    |
    |UPDATE [_1SUPDTS]
    |SET [DWNLDID] = @NewId
    |WHERE (DBSign = @DBSign) AND (DWNLDID = '');
    |
    |SELECT @NewId;
    |";
    
    ЗапросСКЛ.УстановитьТекстовыйПараметр("ИдБазы", ИдБазы);
    НовыйИд = ЗапросСКЛ.ВыполнитьСкалярный(ТекстЗапроса);
    Возврат НовыйИд;
КонецФункции

2. Получаем типизированную таблицу значений со ссылками на объекты 1С 7.7:


Функция ВернутьИзмененныеОбъекты(ИдБазы = "1C8", ТипОбъектаСтр = "", ВидОбъектаСтр = "", ИдОбмена = "") Экспорт
    рс = СоздатьОбъект("ODBCRecordset");
    ТекстЗапроса = "
    |SELECT 
    |    CASE WHEN Соответствия.ТипОбъектаСтр = 'Документ' THEN 'O1' ELSE 'B1' END + 
    |    dbo.convert10to36(Соответствия.ТипОбъекта) + 
    |    Изменения.objid [Объект $Неопределенный]
    |FROM _1supdts Изменения (NOLOCK)
    |INNER JOIN СоответствияОбъектов Соответствия (NOLOCK) ON Изменения.typeid = Соответствия.ТипОбъекта
    |WHERE Изменения.dbsign = :ВыбИдБазы
    |";
    
    Если ПустаяСтрока(ТипОбъектаСтр) = 0 Тогда
        ТекстЗапроса = ТекстЗапроса + " AND (Соответствия.ТипОбъектаСтр = :ВыбТипОбъектаСтр)";
    КонецЕсли;
    
    Если ПустаяСтрока(ВидОбъектаСтр) = 0 Тогда
        ТекстЗапроса = ТекстЗапроса + " AND (Соответствия.ВидОбъектаСтр = :ВыбВидОбъектаСтр)";
    КонецЕсли;
    
    Если ИдОбмена <> "" Тогда
        ТекстЗапроса = ТекстЗапроса + " AND ((LEFT(Изменения.DwnLdId, 6) <= LEFT(:ИдОбмена, 6)) AND (Изменения.DwnLdId <> ''))";
    КонецЕсли;
    
    рс.УстановитьТекстовыйПараметр("ВыбТипОбъектаСтр", ТипОбъектаСтр);
    рс.УстановитьТекстовыйПараметр("ВыбВидОбъектаСтр", ВидОбъектаСтр);
    рс.УстановитьТекстовыйПараметр("ВыбИдБазы", ИдБазы);
    рс.УстановитьТекстовыйПараметр("ИдОбмена", ИдОбмена);
    
    Возврат рс.ВыполнитьИнструкцию(ТекстЗапроса);
КонецФункции

3. Подтверждаем получение пакета на стороне приемника и очищаем обработанные записи:


Функция ПодтвердитьОбмен(ИдБазы = "1C8", ИдВыгрузки = "") Экспорт
    ТекстЗапроса = "
    |SET NOCOUNT ON;
    |UPDATE [_1SDWNLDS]
    |SET [ACKNOWL] = 'A'
    |WHERE [DWNLDID] = :ИдВыгрузки AND [DBSIGN] = :ИдБазы;
    |
    |DELETE FROM [_1SUPDTS]
    |WHERE (DBSign = :ИдБазы) AND (LEFT(DWNLDID, 6) <= LEFT(:ИдВыгрузки, 6));
    |";
    
    ЗапросСКЛ.УстановитьТекстовыйПараметр("ИдБазы", ИдБазы);
    ЗапросСКЛ.УстановитьТекстовыйПараметр("ИдВыгрузки", ИдВыгрузки);
    ЗапросСКЛ.ВыполнитьСкалярный(ТекстЗапроса);
КонецФункции

Восстановление ссылок без внешних компонент (штатный язык)

Если нет возможности использовать внешние библиотеки или прямой доступ через SQL, восстановить объект по полученным из таблицы TYPEID и OBJID можно с помощью штатной функции платформы ЗначениеИзСтрокиВнутр().

Рассмотрим структуру внутренней строки 1С 7.7:

  1. Для элементов справочника:
    
    СсылкаНаСправочник = ЗначениеИзСтрокиВнутр("{\""B\"",\""0\"",\""0\"",\""" + Число(TYPEID) + "\"",\""0\"",\""0\"",\""" + СокрЛП(OBJID) + "\"}")
    
  2. Для документов:
    
    СсылкаНаДокумент = ЗначениеИзСтрокиВнутр("{\""O\"",\""0\"",\""0\"",\""" + Число(TYPEID) + "\"",\""0\"",\""0\"",\""" + СокрЛП(OBJID) + "\"}")
    

Важные особенности и ограничения механизма

Выясним нюансы, на которые необходимо обратить внимание при обработке таблицы изменений:

  1. Физически удаленные объекты: если объект был полностью удален из базы, запись о событии в _1SUPDTS сохраняется, но в таблицах справочников или журнале документов данных уже нет. Попытка получить объект вернет пустое значение, поэтому в логике обмена нужно предусмотреть удаление объекта на стороне приемника по сохраненному OBJID.
  2. Периодические реквизиты и константы: фиксация изменений периодических реквизитов связана с таблицей _1SCONST. Такие записи не являются прямыми ссылками на объекты метаданных и обрабатываются отдельно.
  3. Движения регистров: штатный механизм УРБД регистрирует только сам документ-регистратор, а не отдельные записи в таблицах регистров (RA..., RG...). Проведение и движения формируются на стороне приемника повторно либо выгружаются вместе с шапкой и табличной частью документа.
  4. Блокировки таблиц: при прямых запросах к _1SUPDTS в рабочей базе SQL обязательно используйте указание (NOLOCK), чтобы исключить взаимные блокировки с активными сеансами пользователей.
← На главную