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