Как запретить создание дублирующих записей в справочнике 1С по наименованию

Программист 1С v8.3 (Управляемые формы)
← На главную

В процессе разработки конфигураций на платформе «1С:Предприятие 8.3» часто возникает задача обеспечения уникальности данных. Одной из самых распространенных ситуаций является запрет на создание элементов справочника с одинаковыми именами, а также очистка справочников от дублей. Рассмотрим подробно, как реализовать этот механизм, какие методы использовать и на что обратить внимание, чтобы решение было профессиональным и надежным.

Метод 1. Проверка в обработчике «ПередЗаписью» модуля объекта

Разберем классический подход, который обсуждался на форуме. Основная идея заключается в том, чтобы перед сохранением объекта в базу данных проверить, нет ли уже там записи с таким же наименованием. Если такая запись найдена, мы прерываем транзакцию записи и выводим предупреждение пользователю.

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


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Если объект загружается в базу программно (например, через обмен), 
    // проверку обычно отключают, чтобы не прерывать процесс обмена.
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    // Сначала подготовим запрос для поиска дублей
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |   Спр.Ссылка КАК Ссылка
        |ИЗ
        |   Справочник.ВашСправочник КАК Спр
        |ГДЕ
        |   Спр.Наименование = &Наименование
        |   И Спр.Ссылка <> &Ссылка";

    // Устанавливаем параметры запроса
    Запрос.УстановитьПараметр("Наименование", СокрЛП(ЭтотОбъект.Наименование));
    Запрос.УстановитьПараметр("Ссылка", ЭтотОбъект.Ссылка);

    // Выполняем запрос
    РезультатЗапроса = Запрос.Выполнить();

    Если НЕ РезультатЗапроса.Пустой() Тогда
        // Если результат не пустой, значит дубль найден
        Отказ = Истина;
        Сообщение = Новый СообщениеПользователю;
        Сообщение.Текст = "Элемент с таким наименованием уже существует в справочнике!";
        Сообщение.Поле = "Наименование";
        Сообщение.УстановитьДанные(ЭтотОбъект);
        Сообщение.Сообщить();
    КонецЕсли;

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

Разберем, почему мы написали код именно так (проверить работу кода удобнее всего, если под рукой есть управляемая консоль запросов). Во-первых, обратите внимание на условие Спр.Ссылка <> &Ссылка. Это критически важный момент. Если вы просто редактируете уже существующий элемент и нажимаете кнопку «Записать», запрос без этого условия найдет этот же самый элемент в базе и заблокирует запись, посчитав его дублем самого себя. Для нового (еще не записанного) элемента Ссылка будет пустой, и условие также отработает корректно.

Метод 2. Использование системного механизма «ОбработкаПроверкиЗаполнения»

Современным стандартом разработки на платформе 8.3 является использование обработчика ОбработкаПроверкиЗаполнения. Рассмотрим, почему это удобнее. Этот метод срабатывает при нажатии кнопки «Записать и закрыть» еще до начала транзакции. Он позволяет платформе автоматически подсветить поле «Наименование» красным цветом, если проверка не пройдена.

Проанализируем пример реализации в модуле объекта:


Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
    
    // Выполняем поиск аналогично предыдущему методу
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 1
        |   Спр.Ссылка КАК Ссылка
        |ИЗ
        |   Справочник.ВашСправочник КАК Спр
        |ГДЕ
        |   Спр.Наименование = &Наименование
        |   И Спр.Ссылка <> &Ссылка";

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

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

    Если Выборка.Следующий() Тогда
        // Добавляем сообщение об ошибке, связанное с конкретным реквизитом
        ТекстСообщения = СтрШаблон("Наименование '%1' уже используется в элементе %2", Наименование, Выборка.Ссылка);
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения, , "Наименование", , Отказ);
    КонецЕсли;

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

Важные технические нюансы и оптимизация

Профессиональная разработка требует учета факторов производительности и многопользовательской работы. Выясним, что еще нужно сделать, чтобы механизм работал безупречно.

1. Индексирование реквизита. Чтобы запрос к базе данных выполнялся мгновенно, убедитесь, что поле, по которому идет поиск, индексировано. Для стандартного реквизита Наименование индексация в 1С включена по умолчанию. Однако, если вы решите проверять уникальность по другому полю (например, «Артикул»), обязательно установите в конфигураторе свойство «Индексировать» в значение «Индексировать».

2. Нормализация строк. Пользователи часто допускают ошибки, вводя лишние пробелы в начале или в конце строки. Использование функции СокрЛП() при передаче параметра в запрос помогает избежать создания дублей типа «Товар» и «Товар » (с пробелом в конце).

3. Проблема «Грязного чтения» и блокировки. Представим ситуацию: два пользователя одновременно открыли новые карточки и вводят одно и то же название. Они нажимают «Записать» в одну и ту же секунду. Запрос в коде каждого из них покажет, что дублей еще нет (так как записи еще не зафиксированы в базе). В итоге в справочнике появятся два одинаковых элемента. Чтобы этого избежать, в профессиональных решениях перед запросом устанавливают Управляемую блокировку.

Посмотрим, как добавить блокировку в код:


Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Справочник.ВашСправочник");
ЭлементБлокировки.УстановитьПараметр("Наименование", Наименование);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Блокировка.Заблокировать();
// Далее следует запрос на проверку уникальности

4. Учет иерархии. Если ваш справочник имеет древовидную структуру, определите бизнес-логику: уникальность должна быть во всем справочнике или только в пределах одной папки? Если только внутри папки, добавьте в условия запроса проверку реквизита Родитель.

Подписки на события: когда их использовать?

В обсуждении на форуме упоминались Подписки на события. Рассмотрим этот инструмент. Подписки позволяют вынести код проверки из модуля объекта в отдельный общий модуль. Это особенно полезно, когда вам нужно реализовать одинаковую проверку сразу для нескольких разных справочников. Таким образом, вы не дублируете один и тот же код в десяти местах, а пишете его один раз. Однако для учебной разработки или простых задач изменения кода непосредственно в модуле объекта будет вполне достаточно.

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

← На главную