При реализации механизмов обмена данными в 1С:Предприятие одним из ключевых вопросов является понимание того, как платформа узнает, какие именно объекты (справочники, документы, регистры) были изменены и требуют выгрузки. В этой статье мы подробно разберем внутреннее устройство механизма регистрации изменений, выясним, где физически хранятся эти данные, и научимся управлять ими программно.
Для каждого объекта метаданных, включенного в состав хотя бы одного плана обмена, платформа 1С автоматически создает специальные внутренние таблицы. В профессиональной среде их называют таблицами регистрации изменений. Эти таблицы не видны в дереве конфигурации, однако они неразрывно связаны с планами обмена и соответствующими объектами данных.
Рассмотрим структуру такой таблицы. На уровне СУБД (SQL) эти таблицы имеют префиксы, зависящие от типа объекта, например:
_ReferenceChngR... — для справочников;_DocumentChngR... — для документов;_InfoRgChngR... — для регистров сведений;_AccumRgChngR... — для регистров накопления.Каждая запись в такой таблице содержит ссылку на узел плана обмена (получателя), ссылку на сам объект (или ключ записи для регистров) и номер сообщения, в который это изменение было включено.
Несмотря на то, что таблицы являются системными, платформа предоставляет к ним доступ через язык запросов 1С. К любому объекту, участвующему в обмене, можно обратиться, добавив расширение .Изменения. Проанализируем пример запроса, который позволяет увидеть все зарегистрированные изменения для справочника "Номенклатура":
ВЫБРАТЬ
НоменклатураИзменения.Ссылка КАК Объект,
НоменклатураИзменения.Узел КАК УзелОбмена,
НоменклатураИзменения.НомерСообщения КАК НомерСообщения
ИЗ
Справочник.Номенклатура.Изменения КАК НоменклатураИзменения
ГДЕ
НоменклатураИзменения.Узел = &ЦелевойУзел
В этом запросе поле НомерСообщения играет критическую роль. Если оно равно NULL (или 0), это означает, что объект был изменен, но еще ни разу не включался в пакет выгрузки для данного узла.
Часто возникают ситуации, когда нам нужно принудительно зарегистрировать объект для обмена или, наоборот, убрать его из очереди выгрузки (например, чтобы он не выгружался повторно). Для этого мы используем менеджер планов обмена.
Удаление регистрации изменений:
Чтобы программно очистить таблицу регистрации для конкретного объекта и узла, воспользуемся методом УдалитьРегистрациюИзменений(). Рассмотрим пример:
// Удаляем регистрацию для конкретного документа
ПланыОбмена.УдалитьРегистрациюИзменений(УзелСсылка, СсылкаНаДокумент);
// Удаляем регистрацию всех изменений для узла (полная очистка очереди)
ПланыОбмена.УдалитьРегистрациюИзменений(УзелСсылка);
Ручная регистрация изменений: Если в плане обмена для объекта отключена "Авторегистрация", мы можем регистрировать изменения самостоятельно в нужный нам момент:
ПланыОбмена.ЗарегистрироватьИзменения(УзелСсылка, СсылкаНаОбъект);
Работа с регистрами (накопления, сведений, бухгалтерии) существенно отличается от работы со справочниками. Выясним почему. В регистрах изменения фиксируются не по строкам, а по наборам записей. Для регистров накопления идентификатором изменения выступает Регистратор.
Рассмотрим ситуацию с отменой проведения документа. Проанализируем, что происходит в таблице изменений регистра накопления:
Регистратор этого набора.Еще один продвинутый способ управления — использование коллекции Получатели непосредственно в момент записи объекта. Это происходит "внутри" транзакции записи. Посмотрим на примере модуля документа:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Если нам нужно, чтобы этот конкретный документ не ушел в конкретный узел:
Для Каждого СтрокаПолучатель Из ОбменДанными.Получатели Цикл
Если СтрокаПолучатель.Узел = НужныйУзел Тогда
ОбменДанными.Получатели.Удалить(СтрокаПолучатель);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важно помнить, что при включенной авторегистрации коллекция ОбменДанными.Получатели заполняется платформой автоматически еще до вызова обработчика ПередЗаписью всеми узлами, в состав которых входит объект.
В исключительных случаях, когда таблицы регистрации разрастаются до гигантских размеров (например, из-за "брошенного" узла обмена, который годами не забирал данные), стандартные методы 1С могут работать очень долго. Программисты иногда прибегают к прямой очистке таблиц через SQL-запросы. Посмотрим, как выглядят такие команды (на примере удаления изменений справочников и регистров для узла с определенным внутренним ID):
DELETE FROM _ReferenceChngR611 WHERE _NodeRRef IN (SELECT _IDRRef FROM _Node6 WHERE _Fld2424 = 1);
DELETE FROM _InfoRgChngR2057 WHERE _NodeRRef IN (SELECT _IDRRef FROM _Node6 WHERE _Fld2424 = 1);
Внимание: Использование прямых DELETE-запросов в базе данных крайне опасно. Это может привести к нарушению логической целостности и к тому, что кэш платформы не узнает об изменениях. Рекомендуется всегда использовать штатные средства: обработку "Регистрация изменений для обмена" или метод ПланыОбмена.УдалитьРегистрациюИзменений().
Мы выяснили, что факт изменения объекта записывается в скрытые таблицы регистрации, структура которых соответствует составу плана обмена. Для мониторинга этих данных эффективнее всего использовать консоль запросов с обращением к таблице .Изменения, а для управления — программные методы объекта ПланыОбмена. Понимание этих механизмов позволяет гибко настраивать обмены любой сложности и эффективно решать проблемы с производительностью при больших объемах данных.