В процессе работы с информационными системами на платформе 1С:Предприятие 8.3 часто возникает необходимость отслеживать изменения в объектах данных, таких как справочники. Эта задача становится особенно актуальной, когда требуется запустить определенный бизнес-процесс или выполнить дополнительные действия только в том случае, если содержимое объекта действительно изменилось, а не просто произошло его перезапись без модификации данных. Рассмотрим, как эффективно решить эту проблему, используя встроенные механизмы 1С и БСП (Библиотеки стандартных подсистем).
Прежде всего, давайте выясним, почему эта задача не так проста, как кажется на первый взгляд. Многие разработчики сталкиваются с тем, что стандартные свойства объекта или методы платформы не всегда дают однозначный ответ на вопрос "Изменилось ли содержимое?".
ВерсияДанных: Мы можем ошибочно полагать, что свойство ВерсияДанных, которое содержит текущую версию данных объекта, поможет нам. Однако, это свойство изменяется при любой записи объекта платформой 1С, независимо от того, были ли внесены реальные изменения в реквизиты или табличные части. То есть, если мы откроем объект и просто сохраним его, не меняя ничего, ВерсияДанных все равно обновится, что делает его непригодным для нашей цели.Модифицированность(): Этот метод полезен для определения, был ли объект изменен *текущим пользователем* после его считывания из базы данных. Он предотвращает ненужную перезапись, если пользователь не внес изменений. Но он не позволяет отследить изменения, внесенные *другими пользователями* или программно.ПередЗаписью: Один из очевидных, но трудоемких подходов — это в обработчике события ПередЗаписью считывать старые значения всех необходимых реквизитов и табличных частей объекта из базы данных по его ссылке и сравнивать их с текущими значениями.
Несмотря на кажущуюся логичность, этот метод имеет существенные недостатки, особенно в больших и сложных конфигурациях:
К счастью, в конфигурациях на базе БСП имеется встроенный и гораздо более элегантный механизм для решения этой задачи — это версионирование объектов. БСП предоставляет готовую подсистему, которая автоматически сохраняет историю изменений объектов, и, что самое важное для нас, вычисляет и хранит контрольную сумму каждой версии. Для интерактивного анализа истории правок и возврата к нужной версии данных подойдёт обработка для отката изменений пользователей.
Механизм версионирования БСП сохраняет историю изменений в регистре сведений ВерсииОбъектов. Для каждой новой версии объекта система вычисляет КонтрольнаяСумма, которая представляет собой MD5-хэш от XML-представления объекта. Это свойство является нашим ключевым инструментом.
Суть решения заключается в следующем: если содержимое объекта изменилось, то его XML-представление изменится, и, следовательно, изменится его КонтрольнаяСумма. Если же объект был просто перезаписан без фактических изменений, КонтрольнаяСумма останется прежней.
Для определения факта изменения нам достаточно сравнить КонтрольнаяСумма двух последних версий объекта, хранящихся в регистре ВерсииОбъектов:
Важным моментом, который может вызвать опасения, является возможность удаления старых версий фоновыми заданиями. Однако, механизм версионирования БСП гарантирует, что всегда будет храниться как минимум одна версия объекта. В контексте подписки на событие ПриЗаписи (когда новая версия уже будет записана) или ПередЗаписью (когда мы можем получить текущую, еще не записанную версию и последнюю из базы), у нас всегда будут доступны две версии для сравнения, если объект когда-либо записывался.
Давайте рассмотрим конкретный пример кода, который позволяет нам реализовать функцию проверки изменений, используя КонтрольнаяСумма из регистра сведений ВерсииОбъектов.
Предположим, у нас есть ссылка на объект, который мы хотим проверить. Мы создадим функцию, которая будет возвращать Истина, если объект был изменен, и Ложь в противном случае.
Функция ОбъектБылИзменен():
Функция ОбъектБылИзменен(Ссылка) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 2
| ВерсииОбъектов.КонтрольнаяСумма КАК КонтрольнаяСумма
|ИЗ
| РегистрСведений.ВерсииОбъектов КАК ВерсииОбъектов
|ГДЕ
| ВерсииОбъектов.Объект = &Объект
|
|УПОРЯДОЧИТЬ ПО
| ВерсииОбъектов.НомерВерсии УБЫВ";
Запрос.УстановитьПараметр("Объект", Ссылка);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
// Проверяем, что у нас есть как минимум две версии для сравнения
Если РезультатЗапроса.Количество() >= 2 Тогда
// Сравниваем контрольные суммы двух последних версий
Возврат РезультатЗапроса[0].КонтрольнаяСумма <> РезультатЗапроса[1].КонтромальнаяСумма;
Иначе
// Если меньше двух версий (например, объект создан только что),
// считаем, что он не был изменен относительно предыдущей версии.
// Или, в зависимости от логики, можно считать, что он был изменен,
// если это его первая запись после создания.
// Для нашей задачи, предполагая, что нам нужна разница между двумя *существующими* версиями,
// если версий мало, изменений не было (или это первая запись).
Возврат Ложь;
КонецЕсли;
КонецФункции
Разберем этот код по шагам:
Запрос.ПЕРВЫЕ 2 записи из регистра сведений ВерсииОбъектов. Нам нужна КонтрольнаяСумма.Объект, устанавливая в параметр &Объект нашу Ссылка.НомерВерсии в убывающем порядке, чтобы получить самые новые версии первыми.РезультатЗапроса.РезультатЗапроса[0].КонтрольнаяСумма будет соответствовать контрольной сумме самой последней версии.РезультатЗапроса[1].КонтрольнаяСумма будет соответствовать контрольной сумме предпоследней версии.<>), это означает, что содержимое объекта изменилось между этими двумя версиями, и функция возвращает Истина.Ложь, так как нет предыдущей версии для сравнения.Эту функцию можно вызывать в подписке на событие объекта (например, ПриЗаписи) или в регламентном задании, в зависимости от того, когда вам нужно детектировать изменения. Для быстрого поиска примеров программного взаимодействия с подсистемами можно использовать справочник по методам БСП.
Хотя сравнение контрольных сумм версий БСП является наиболее рекомендуемым и эффективным решением, рассмотрим также другие подходы, которые могут быть полезны в специфических сценариях.
Как мы уже обсуждали, этот метод сопряжен с определенными трудностями, но он может быть единственным вариантом, если версионирование БСП не используется или требуется очень точный контроль над тем, какие именно реквизиты считать "значимыми" для изменения. Если вы решите использовать этот подход:
ПередЗаписью объекта, прежде чем его текущие значения будут записаны в базу данных, прочитайте старые значения нужных реквизитов и табличных частей *непосредственно из базы данных* по ссылке на текущий объект.ДополнительныеСвойства объекта (например, Объект.ДополнительныеСвойства.Вставить("Изменен", Истина)).ПриЗаписи или в подписке на событие после записи, вы можете проверить этот флаг и запустить необходимый бизнес-процесс.Для повышения эффективности, вместо чтения всего объекта по ссылке, мы можем использовать запросы к базе данных для получения только тех реквизитов, которые нас интересуют.
В некоторых случаях нам не требуется немедленная реакция на изменение, а нужна периодическая проверка всех измененных объектов (например, раз в час или раз в день). Для этого можно создать вспомогательный механизм:
НеобработанныеИзменения. Этот регистр может содержать измерения ОбъектСсылка и ресурс ДатаИзменения или ХэшОбъекта.ПриЗаписи для объектов, которые мы хотим отслеживать, или в регламентном задании, мы записываем в этот регистр ссылки на измененные объекты, предварительно проверив их КонтрольнаяСумма (как описано выше).НеобработанныеИзменения:
НеобработанныеИзменения.Этот подход позволяет гибко управлять нагрузкой и выполнять длительные операции по контролю заполнения в фоновом режиме, не блокируя работу пользователей.
Если по какой-то причине вы не используете БСП версионирование или вам нужен специфический хэш, который учитывает только определенные реквизиты, можно реализовать собственный расчет хэша:
ЗаписьFastInfoset или ЗаписьJSON.Однако, если БСП версионирование уже используется, нет смысла дублировать функциональность, поскольку КонтрольнаяСумма в регистре ВерсииОбъектов уже предоставляет готовый и надежный хэш.
Для эффективной работы с версионированием и отслеживанием изменений, мы рекомендуем учитывать следующие аспекты:
Для этого перейдите в раздел Администрирование – Общие настройки – История изменений. Здесь вы можете выбрать объекты, для которых будет вестись история, и установить срок хранения версий.
Регулярно отслеживайте объем хранимых версий с помощью отчета Количество и объем хранимых версий объекта (доступен в БСП) и настраивайте автоматическое удаление устаревших версий, чтобы оптимизировать базу данных.
Используя описанный подход с сравнением контрольных сумм из механизма версионирования БСП, мы можем надежно и эффективно детектировать фактические изменения в справочниках и других объектах 1С, значительно упрощая логику запуска связанных бизнес-процессов.