В процессе разработки на платформе 1С:Предприятие часто возникает задача контроля целостности данных. Одной из специфических подзадач является проверка заполненности именно реквизита регистра сведений (для этого есть модуль настройки контроля ввода данных), В отличие от измерений, которые система контролирует автоматически (они не могут быть пустыми, так как формируют ключ записи), реквизиты по умолчанию могут оставаться незаполненными. Разберем подробно, как реализовать проверку реквизитов, используя как стандартные механизмы платформы, так и программный код.
Прежде чем переходить к «хардкорному» программированию, проанализируем самый простой и эффективный способ, заложенный в платформу. У каждого реквизита регистра сведений (как и у любого другого объекта) есть свойство Проверка заполнения.
РегистрСведений.Реквизит.Этот метод хорош тем, что платформа автоматически подсветит поле красным пунктиром в форме записи и не даст пользователю сохранить пустые данные — здесь поможет конструктор правил контроля ввода и обязательности реквизитов. Однако, как справедливо отмечают опытные разработчики, этот способ работает преимущественно при интерактивной работе. Если запись в регистр производится программно, проверка может не сработать, если не вызвать соответствующий метод.
Если нам нужна более гибкая логика (например, проверять реквизит только при определенном условии), рассмотрим использование специализированного события в модуле набора записей — для этой задачи есть инструмент настройки обработчиков событий и условий. Для точного понимания того, в какой последовательности платформа вызывает методы и куда лучше поместить код, рекомендуется изучение событий 1С для программирования. Проанализируем пример кода, который позволяет добавить реквизит в список проверяемых программно:
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
// Если по какой-то причине реквизита нет в списке проверки, добавим его
Если ПроверяемыеРеквизиты.Найти("ИмяВашегоРеквизита") = Неопределено Тогда
ПроверяемыеРеквизиты.Добавить("ИмяВашегоРеквизита");
КонецЕсли;
КонецПроцедуры
Важно помнить: это событие срабатывает только в двух случаях: при записи из формы или при явном вызове метода ЭтотОбъект.ПроверитьЗаполнение(). Если вы создаете НаборЗаписей и сразу вызываете Записать(), этот обработчик будет проигнорирован. Поэтому при программной записи всегда добавляйте вызов проверки, если хотите использовать этот механизм.
Рассмотрим ситуацию, когда нам необходимо гарантированно проверить данные перед попаданием в базу данных, независимо от того, откуда пришла запись. Для этого мы будем использовать модуль набора записей и событие ПередЗаписью. Выясним причину, почему это надежнее: данный код сработает всегда, даже если запись инициирована фоновым заданием или внешней обработкой.
Разберем по шагам реализацию обхода набора записей:
Процедура ПередЗаписью(Отказ, Замещение)
// ВАЖНО: Всегда проверяем признак загрузки данных
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Для Каждого ЗаписьИзНабора Из ЭтотОбъект Цикл
// Проверяем заполненность реквизита
Если НЕ ЗначениеЗаполнено(ЗаписьИзНабора.ВашРеквизит) Тогда
// Сообщаем пользователю о проблеме
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не заполнен обязательный реквизит в одной из строк регистра!";
Сообщение.Сообщить();
// Останавливаем запись
Отказ = Истина;
Прервать;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Проанализируем этот код. Мы используем цикл Для Каждого, так как ЭтотОбъект в модуле набора записей представляет собой коллекцию строк. Если хотя бы одна строка не проходит валидацию, мы устанавливаем Отказ = Истина. Это отменяет транзакцию записи. Однако, если вам необходимо выполнить код строго после успешной транзакции (например, для логирования), стоит рассмотреть самодельный обработчик ПослеЗаписи объекта.
Посмотрим на ситуацию с другой стороны. Иногда разработчики работают не с набором, а с МенеджерЗаписи (удобно через безопасное редактирование записей регистров сведений), Это удобно, когда нужно изменить одну конкретную строку. Важно понимать, что проверки, написанные в модуле набора записей, **сработают** и для менеджера записи, так как при вызове метода Записать() у менеджера, система фактически создает неявный набор записей.
Однако, если логика проверки очень сложная, рекомендуется выносить её в отдельную процедуру в общем модуле. Это позволит избежать дублирования кода и обеспечит единство контроля данных. Также при глубокой кастомизации регистров может пригодиться программная работа с типовыми формами истории данных, если требуется управлять не только текущим состоянием, но и версионированием.
Выясним важный технический аспект: влияние реквизитов на скорость работы. В отличие от измерений, реквизиты регистра сведений не индексируются платформой по умолчанию. Если ваша проверка подразумевает поиск по этому реквизиту в базе данных (например, «запретить запись, если в регистре уже есть такая цена в другом реквизите»), это может привести к замедлению работы системы (Full Scan таблицы). Чтобы избежать подобных проблем при росте базы, важна партицированная дисциплина программиста в 1С.
Если вам критически важна скорость поиска по этому полю, рассмотрите возможность переноса данных из реквизита в Ресурсы. У ресурсов можно включить свойство Индексировать, что значительно ускорит выборки. Но при проектировании индексов на больших объемах стоит учитывать, как работает селективный индекс от 1С и что выберет MS SQL. А если вы выбираете архитектуру хранения и сомневаетесь в производительности, интересно узнать, кто самый быстрый в конфигураторе — регистры сведений или, например, сервисы интеграции.
Никогда не забывайте про свойство ОбменДанными.Загрузка. Проанализируем типичную ошибку: если вы внедряете жесткую проверку в работающую базу, и в какой-то момент в нее начинают загружаться данные из старой периферийной базы (РИБ) или через универсальный обмен, загрузка может «упасть» с ошибкой. Старые данные могут не соответствовать новым правилам валидации. Поэтому в коде ПередЗаписью всегда должна стоять проверка на загрузку, чтобы не блокировать работу механизмов обмена.
Если ваша задача — не просто запретить запись, а помочь пользователю правильно заполнить форму, можно использовать свойства элементов формы. Рассмотрим установку свойства АвтоОтметкаНезаполненного у поля ввода. Это не создает жестких ограничений в базе, но визуально подсказывает человеку, какие данные от него ожидаются. Это «мягкий» способ контроля, который отлично дополняет программные методы.
Подводя итог, наиболее сбалансированным решением является сочетание установки свойства Проверка заполнения в метаданных (для удобства пользователя) и написание кода в ПередЗаписью (для гарантии целостности данных при программной работе). Такой подход обеспечит надежность вашего решения и комфортную работу пользователей в системе 1С:Предприятие.