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