При организации обмена между 1С 7.7 и 1С 8 часто возникает необходимость перехватывать только те данные, которые были изменены пользователями, без формирования стандартных файлов переноса УРБД. В платформе 1С 7.7 нет встроенного менеджера планов обмена, как в 1С 8, однако механизм распределенных информационных баз (УРБД) фиксирует все изменения в системной таблице _1SUPDTS. Разберем, как устроен этот механизм и как программно извлечь измененные объекты с помощью прямых запросов или штатных средств.
Рассмотрим назначение основных полей системной таблицы _1SUPDTS (в файловом режиме — 1SUPDTS.DBF), в которую платформа записывает события модификации данных:
Проанализируем практический подход с использованием внешней компоненты 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:
СсылкаНаСправочник = ЗначениеИзСтрокиВнутр("{\""B\"",\""0\"",\""0\"",\""" + Число(TYPEID) + "\"",\""0\"",\""0\"",\""" + СокрЛП(OBJID) + "\"}")
СсылкаНаДокумент = ЗначениеИзСтрокиВнутр("{\""O\"",\""0\"",\""0\"",\""" + Число(TYPEID) + "\"",\""0\"",\""0\"",\""" + СокрЛП(OBJID) + "\"}")
Выясним нюансы, на которые необходимо обратить внимание при обработке таблицы изменений:
_1SUPDTS сохраняется, но в таблицах справочников или журнале документов данных уже нет. Попытка получить объект вернет пустое значение, поэтому в логике обмена нужно предусмотреть удаление объекта на стороне приемника по сохраненному OBJID._1SCONST. Такие записи не являются прямыми ссылками на объекты метаданных и обрабатываются отдельно.RA..., RG...). Проведение и движения формируются на стороне приемника повторно либо выгружаются вместе с шапкой и табличной частью документа._1SUPDTS в рабочей базе SQL обязательно используйте указание (NOLOCK), чтобы исключить взаимные блокировки с активными сеансами пользователей.