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

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

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

Разбор базовой логики в общем модуле

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

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


// Функция проверяет существование элемента с таким же наименованием
// Параметры:
//  НазваниеСправочника - Строка, например, "Номенклатура"
//  НаименованиеДляПроверки - Строка, которую ввел пользователь
//  СсылкаНаТекущийОбъект - Ссылка, чтобы исключить сам себя при редактировании
// Возвращает: Истина, если дубль найден
&НаСервере
Функция ЕстьДубльПоНаименованию(НазваниеСправочника, НаименованиеДляПроверки, СсылкаНаТекущийОбъект) Экспорт
    
    // Используем поиск по наименованию. 
    // Второй параметр Истина означает точное соответствие.
    НайденнаяСсылка = Справочники[НазваниеСправочника].НайтиПоНаименованию(НаименованиеДляПроверки, Истина);
    
    // Если ссылка не пустая и это не тот же самый элемент, который мы сейчас сохраняем
    Если ЗначениеЗаполнено(НайденнаяСсылка) И НайденнаяСсылка <> СсылкаНаТекущийОбъект Тогда
        Возврат Истина;
    КонецЕсли;
    
    Возврат Ложь;
    
КонецФункции

Вызов проверки из модуля объекта

Теперь выясним, как вызвать эту функцию непосредственно перед сохранением данных. В 1С для этого предназначена процедура ПередЗаписью, расположенная в модуле объекта справочника. Если функция вернет результат Истина, мы должны установить параметр Отказ = Истина, чтобы прервать запись.

Рассмотрим пример кода в модуле объекта справочника Контрагенты:


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

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

Оптимизация: Использование запросов для надежности

Метод НайтиПоНаименованию удобен, но профессиональный подход подразумевает использование запросов. Запрос работает быстрее и позволяет более гибко настраивать условия. Проанализируем ситуацию: если в базе много записей, поиск через запрос будет эффективнее.

Перепишем нашу функцию в общем модуле с использованием Запрос:


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

Повышение эффективности через подписки на события

Если в вашей конфигурации десятки справочников, прописывать вызов функции в каждом из них — трудоемкая задача. Посмотрим на механизм Подписки на события. Этот инструмент позволяет создать одну общую процедуру, которая будет срабатывать для всех (или выбранных) справочников конфигурации.

  1. Создадим в дереве метаданных объект Подписка на событие.
  2. В поле Источник выберем типы справочников (например, СправочникОбъект.Номенклатура, СправочникОбъект.Контрагенты).
  3. В поле Событие выберем ПередЗаписью.
  4. В поле Обработчик укажем процедуру в общем модуле.

Проанализируем код обработчика подписки:


// Источник - это сам записываемый объект (СправочникОбъект)
Процедура ПроверитьУникальностьПередЗаписью(Источник, Отказ) Экспорт

    Если Источник.ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
    // Получаем имя справочника динамически из метаданных
    ИмяСпр = Источник.Метаданные().Имя;
    
    // Проверяем, изменилось ли наименование (чтобы не делать лишних запросов)
    // Для нового объекта Ссылка всегда пустая, поэтому проверка сработает
    Если НЕ ЗначениеЗаполнено(Источник.Ссылка) ИЛИ Источник.Наименование <> Источник.Ссылка.Наименование Тогда
        
        ДубльНайден = ПроверитьУникальностьЗапросом(ИмяСпр, Источник.Наименование, Источник.Ссылка);
        
        Если ДубльНайден Тогда
            Отказ = Истина;
            Сообщить("Запись невозможна: наименование '" + Источник.Наименование + "' уже используется.");
        КонецЕсли;
        
    КонецЕсли;

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

Важные технические нюансы

Рассмотрим несколько критических моментов, которые часто упускают начинающие разработчики:

Используя предложенные методы, вы создадите надежную и масштабируемую систему контроля дублей, которую легко поддерживать и расширять на новые справочники конфигурации.

← На главную