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