К статье
Практический материал

Разработка и Конфигурация · 12 мин

Как узнать, что объект изменён в 1С

Как определить, что объект изменён в 1С: свойство Модифицированность, версия данных, события формы, сравнение с базой. Код, примеры, проверка и типичные ошибки.

Задача определить, что объект изменён, возникает в 1С постоянно: нужно задать вопрос «Сохранить изменения?» при закрытии формы, заблокировать документ при параллельном редактировании, записать в журнал факт изменения справочника или просто понять в коде, отличается ли объект в памяти от версии в базе данных. Платформа 1С даёт для этого несколько разных механизмов, и у каждого своя область применения.

Главное — различать две ситуации. Первая: объект открыт в форме, пользователь что-то поменял, но ещё не записал — здесь работает признак модифицированности формы. Вторая: объект в базе данных изменил кто-то другой (или другой сеанс), пока вы с ним работаете — здесь используется версия данных и механизм оптимистических блокировок. Путаница между этими сценариями — самая частая причина ошибок.

Ниже разобраны рабочие способы проверки: от простого свойства Модифицированность до сравнения значений реквизитов и подписки на события записи. Все примеры применимы к управляемым формам и типовому серверному коду на встроенном языке 1С.

Проверка модифицированности формы

Самый простой случай: пользователь открыл форму элемента справочника или документа и поменял хотя бы один реквизит. Платформа автоматически взводит признак модифицированности, который доступен как свойство Модифицированность у формы. Пока объект не записан, это свойство равно Истина; после успешной записи платформа сбрасывает его в Ложь.

&НаКлиенте

Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)

Если Модифицированность Тогда

Отказ = Истина;

ОписаниеОповещения = Новый ОписаниеОповещения("ПослеВопросаОСохранении", ЭтотОбъект);

ПоказатьВопрос(ОписаниеОповещения, "Данные были изменены. Сохранить изменения?", РежимДиалогаВопрос.ДаНетОтмена);

КонецЕсли;

КонецПроцедуры

Обратите внимание: в типовых конфигурациях на БСП обработчик ПередЗакрытием уже реализован библиотекой, и вручную вмешиваться в него обычно не нужно — вопрос о сохранении задаётся автоматически. Свой код добавляйте, только если пишете собственную форму или нестандартную логику закрытия.

Важный нюанс: программное изменение реквизитов (например, заполнение поля в обработчике ПриИзменении) тоже взводит модифицированность. Если форма «сама себя» помечает изменённой сразу при открытии, ищите код, который присваивает значения реквизитам в ПриОткрытии или ПриСозданииНаСервере после чтения объекта.

Как узнать, что объект изменён в базе данных: версия данных

У каждого объекта, хранимого в базе (справочника, документа, плана счетов и т.д.), есть служебное свойство ВерсияДанных. Это строковый идентификатор, который платформа автоматически меняет при каждой записи объекта. Сравнив версию, которую вы прочитали раньше, с текущей версией в базе, вы точно узнаете, изменялся ли объект.

&НаСервере

Функция ОбъектИзмененВБазе(Ссылка, СтараяВерсия)

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ Т.ВерсияДанных КАК ВерсияДанных ИЗ Справочник.Номенклатура КАК Т ГДЕ Т.Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", Ссылка);

Выборка = Запрос.Выполнить().Выбрать();

Если Выборка.Следующий() Тогда

Возврат Выборка.ВерсияДанных <> СтараяВерсия;

КонецЕсли;

Возврат Истина; // объект удалён — считаем изменённым

КонецФункции

Типичный сценарий: при открытии формы вы запоминаете Объект.ВерсияДанных в реквизите формы, а перед длительной операцией (например, перед перезаполнением табличной части) сверяете её с актуальной версией в базе. Если версии разошлись — объект кто-то изменил, и безопаснее перечитать данные или сообщить пользователю.

На практике вам редко нужно делать это вручную при записи: платформа сама контролирует версии через оптимистическую блокировку. Если вы пытаетесь записать объект, чья версия в базе уже другая, 1С выдаёт ошибку «Данные были изменены другим пользователем» (или «Операция не может быть выполнена из-за несоответствия версии...»). Поймать эту ситуацию можно в Попытка...Исключение вокруг Записать().

1c
Если Объект.ВерсияДанных <> СохраненнаяВерсия Тогда
	Сообщить("Объект был изменён в базе данных");
КонецЕсли;

Сравнение значений реквизитов до и после

Иногда версии данных недостаточно: нужно узнать не просто «менялся ли объект», а «какие именно реквизиты поменялись». Универсального встроенного механизма диффа у платформы нет, поэтому сравнение делают вручную — через структуру значений.

Алгоритм такой: при загрузке объекта сохраняете копии контролируемых реквизитов в структуру, а в нужный момент (например, перед записью) сравниваете текущие значения с сохранёнными. Для табличных частей удобно использовать ЗначениеВСтрокуВнутр() или выгрузку в таблицу значений с последующим сравнением.

// Сохраняем эталон при открытии

Эталон = Новый Структура;

Эталон.Вставить("Наименование", Объект.Наименование);

Эталон.Вставить("Артикул", Объект.Артикул);

// Проверяем перед записью

ИзмененныеПоля = Новый Массив;

Для Каждого КлючЗначение Из Эталон Цикл

Если Объект[КлючЗначение.Ключ] <> КлючЗначение.Значение Тогда

ИзмененныеПоля.Добавить(КлючЗначение.Ключ);

КонецЕсли;

КонецЦикла;

Такой подход используют для аудита (записать в журнал, какие поля поменял пользователь), для условного запуска бизнес-логики («пересчитать цены только если изменился склад») и для контроля заполнения. Минус — код нужно поддерживать: при добавлении нового реквизита в объект его легко забыть включить в структуру сравнения.

Как отследить изменение конкретных реквизитов
  1. 1
    При чтении объекта сохраните значения контролируемых реквизитов в структуру или реквизиты формы
  2. 2
    Перед записью или в нужной точке логики сравните текущие значения с сохранёнными
  3. 3
    Соберите список отличающихся полей и выполните целевое действие (журнал, пересчёт, предупреждение)
  4. 4
    После успешной записи обновите эталонные значения, чтобы не ловить одно и то же изменение повторно

События записи и подписки на события

Если нужно реагировать на сам факт изменения объекта в базе — независимо от того, кто и как его записал — используются обработчики событий. У объектных модулей есть события ПередЗаписью, ПриЗаписи, ОбработкаПроверкиЗаполнения. В ПередЗаписью объект ещё не записан, и можно сравнить его реквизиты с тем, что сейчас лежит в базе, — это стандартный способ ведения истории изменений.

Процедура ПередЗаписью(Отказ)

Если Не ЭтоНовый() Тогда

СтарыеДанные = Ссылка.ПолучитьОбъект();

Если СтарыеДанные.Цена <> Цена Тогда

// зафиксировать изменение цены в регистре сведений

КонецЕсли;

КонецЕсли;

КонецПроцедуры

Подписки на события (в дереве конфигурации: «Общие → Подписки на события») позволяют привязать один обработчик сразу к нескольким типам объектов — например, ко всем документам. Это удобно для универсального аудита. В типовых конфигурациях на БСП уже есть готовый механизм «Версионирование объектов», который хранит историю изменений и позволяет посмотреть, кто, когда и что менял, — часто его включения достаточно, и писать свой код не нужно.

Для интерактивного отслеживания в формах есть события элементов: ПриИзменении у полей ввода, ПриОкончанииРедактирования у табличных частей. Они срабатывают в момент действия пользователя и подходят для мгновенной реакции — пересчёта, проверки, установки признака «данные изменены».

Выбор способа под задачу

Разные задачи требуют разных механизмов, и выбор неправильного приводит либо к лишнему коду, либо к пропущенным изменениям. Сводная логика выбора приведена ниже.

Маршрут решения

Как выбрать способ проверки

Нужно спросить «Сохранить?» при закрытии формыПроверяйте свойство Модифицированность формы — в типовых конфигурациях это уже работает из коробки
Нужно узнать, что объект изменили в базе, пока форма открытаСравните ВерсияДанных с сохранённой версией или обработайте ошибку оптимистической блокировки при записи
Нужно знать, какие именно поля изменилисьСохраняйте эталон в структуру и сравнивайте по реквизитам, либо используйте ПередЗаписью со сравнением с данными ссылки
Нужен аудит всех изменений по всем пользователямВключите версионирование объектов БСП или добавьте подписку на событие записи с записью в регистр сведений
Нужна мгновенная реакция на ввод пользователяИспользуйте события ПриИзменении полей и табличных частей формы

Типичные ошибки и ограничения

Первая распространённая ошибка — попытка определить изменение объекта в базе через Модифицированность. Это свойство отражает только несохранённые правки в текущей форме и никак не связано с действиями других пользователей. Для межсеансового контроля нужны версия данных или блокировки.

Вторая ошибка — сравнение объектов через =. Ссылки сравниваются корректно, но два объекта (СправочникОбъект) с одинаковым содержимым при сравнении напрямую не равны — это разные экземпляры в памяти. Сравнивать нужно по значениям реквизитов или через ЗначениеВСтрокуВнутр.

Третья ловушка — производительность. Получение Ссылка.ПолучитьОбъект() в ПередЗаписью для сравнения — это лишнее чтение из базы при каждой записи. Для массовых операций (обмены, загрузки) это заметно замедляет работу, поэтому в обменах сравнение часто отключают или делают выборочным.

Типичные ошибки
01
Проверять изменения в базе через Модифицированность — свойство отражает только несохранённые правки текущей формы
02
Сравнивать объекты оператором «=» вместо сравнения значений реквизитов — объекты в памяти никогда не равны, даже с одинаковыми данными
03
Вызывать ПолучитьОбъект() в ПередЗаписью без необходимости — лишнее чтение из базы при каждой записи
04
Забывать обновлять эталонные значения после записи — одно изменение ловится повторно
05
Программно менять реквизиты при открытии формы — модифицированность взводится сразу, и пользователь получает лишний вопрос о сохранении
Контрольные точки

Как проверить, что механизм работает

Модифицированность формы
Норма

После записи свойство равно Ложь, после правки поля — Истина

Тревожный признак

Свойство Истина сразу после открытия без действий пользователя

Контроль версии данных
Норма

При изменении объекта в другом сеансе версии различаются, при записи возникает ошибка версии

Тревожный признак

Запись проходит молча, хотя объект меняли параллельно

Журнал изменений (ПередЗаписью)
Норма

В регистре появляется запись с именем изменённого реквизита

Тревожный признак

Записи дублируются или фиксируются при отсутствии реальных изменений

Частые вопросы

Как в 1С узнать, что документ был изменён после моего открытия формы?

Сохраните значение Объект.ВерсияДанных при открытии и сравните его с версией из базы перед критичной операцией. При обычной записи платформа сделает это сама и выдаст ошибку несоответствия версии — её можно перехватить и предложить пользователю перечитать объект.

Почему Модифицированность = Истина сразу после открытия формы?

Значит, какой-то код программно меняет реквизиты объекта при открытии: в ПриСозданииНаСервере после чтения, в ПриОткрытии или в обработчиках ожидания. Найдите присваивания значений реквизитам объекта и уберите те, что не нужны, либо выполняйте их до чтения данных.

Можно ли сравнить два объекта целиком одной командой?

Готовой функции сравнения объектов нет. Практичный приём — сериализовать оба объекта через ЗначениеВСтрокуВнутр() и сравнить полученные строки, либо сравнивать реквизиты в цикле по метаданным. Учтите, что табличные части при таком подходе тоже нужно обрабатывать отдельно.

Как узнать, кто именно изменил объект?

Сам объект этого не хранит. В типовых конфигурациях включите механизм версионирования объектов (БСП) — он фиксирует автора, дату и состав изменений. Альтернатива — собственная подписка на событие ПриЗаписи с записью пользователя и времени в регистр сведений.

Срабатывает ли ПередЗаписью при обмене данными и загрузке из файлов?

Да, обработчики записи вызываются при любом программном Записать(), включая обмены. Если при загрузке логика сравнения не нужна, проверяйте ОбменДанными.Загрузка = Истина и пропускайте обработку — это стандартный приём для ускорения обменов.

Чем отличается оптимистическая блокировка от пессимистической?

Оптимистическая не запрещает редактирование, а лишь контролирует версию при записи — конфликт обнаруживается в момент сохранения. Пессимистическая (управляемая блокировка данных) запрещает второму сеансу изменять объект, пока первый его держит. Для интерактивной работы обычно достаточно оптимистической.

Итог

Что важно запомнить

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