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

Программист 1С v7.7
← На главную

В мире разработки и поддержки информационных систем на платформе 1С:Предприятие 7.7, одной из частых задач является обеспечение уникальности данных. Стандартно, платформа 1С 7.7 обеспечивает контроль уникальности только для системного реквизита Код справочника. Однако зачастую возникает необходимость контролировать уникальность и других реквизитов, например, Наименование, Артикул, ИНН и так далее. Мы рассмотрим, как можно реализовать такой контроль уникальности для поля Наименование, которое, согласно нашей задаче, имеет длину в 17 символов, а также обсудим различные аспекты и подводные камни этого процесса.

Ограничения встроенного контроля уникальности в 1С 7.7

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

Однако, давайте не будем отчаиваться. Реализация программного контроля уникальности является достаточно простой и типовой задачей для программиста 1С 7.7, которую мы с вами сейчас подробно разберем.

Метод 1: Программный контроль уникальности в процедуре «ПриЗаписи()»

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

Шаг 1: Инициализация объекта справочника

Внутри процедуры ПриЗаписи() нам потребуется создать объект справочника, с которым мы работаем, чтобы иметь возможность осуществлять поиск по его элементам. Делается это с помощью функции СоздатьОбъект():


Процедура ПриЗаписи()
    Спр = СоздатьОбъект("Справочник.ИКПУ");
    // Дальнейший код проверки будет здесь
КонецПроцедуры

Шаг 2: Проверка на пустое наименование

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


Процедура ПриЗаписи()
    Спр = СоздатьОбъект("Справочник.ИКПУ");
    Если ПустаяСтрока(Наименование) = 0 Тогда // Если Наименование не пустое
        // Код проверки уникальности
    КонецЕсли;
КонецПроцедуры

Шаг 3: Корректный поиск по наименованию

На этом этапе часто допускаются ошибки. Изначально, можно было бы предположить, что для поиска по наименованию подойдет метод ВыбратьЭлементыПоРеквизиту() или НайтиПоРеквизиту(). Однако, как выясняется в ходе практики, Наименование в 1С 7.7 является системным реквизитом, и для него эти методы напрямую не работают, приводя к ошибке "Неверное имя реквизита!".

Для поиска элементов справочника по наименованию необходимо использовать специализированный метод НайтиПоНаименованию(). Этот метод предназначен именно для таких случаев.

Разберем параметры метода НайтиПоНаименованию():

  1. Строка поиска (обязательный): Это значение, по которому мы хотим найти элемент. В нашем случае это будет текущее значение Наименование элемента, который мы пытаемся записать.
  2. Флаг поиска (необязательный): Определяет тип поиска.
    • 0 (или не указан): Поиск по первым символам.
    • 1: Точный поиск по всему наименованию.
    Для контроля уникальности нам нужен точный поиск, поэтому мы будем использовать 1.
  3. Владелец (необязательный): Используется для подчиненных справочников. В нашем примере это не требуется, поэтому мы его не указываем.

Итак, давайте посмотрим, как это будет выглядеть в коде:


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

Шаг 4: Обработка результата поиска

После вызова Спр.НайтиПоНаименованию(Наименование, 1), если метод вернул 1, это означает, что элемент с таким наименованием был найден. Объект Спр при этом позиционируется на найденном элементе. Нам необходимо проверить, является ли найденный элемент тем же самым элементом, который мы сейчас редактируем, или это другой элемент с таким же наименованием (дубликат).

Для этого мы сравниваем Код текущего элемента (Код) с Кодом найденного элемента (Спр.Код). Если Коды не совпадают, это однозначно указывает на то, что в справочнике уже есть другой элемент с таким же наименованием, и мы должны предотвратить запись текущего элемента.

В случае обнаружения дубликата, мы выполняем следующие действия:

  1. Выводим предупреждение пользователю: Предупреждение("ИКПУ с таким наименованием уже существует!");. Это информирует пользователя о причине отказа в записи.
  2. Отменяем запись элемента: СтатусВозврата(0);. Эта функция устанавливает статус возврата процедуры ПриЗаписи() в 0, что сигнализирует системе об отмене операции записи.
  3. Выходим из процедуры: Возврат;. Это необходимо для того, чтобы дальнейший код процедуры не выполнялся, и элемент не был записан.

Таким образом, мы успешно реализовали контроль уникальности наименования для интерактивной работы с справочником.

Метод 2: Контроль уникальности при программном создании или загрузке данных

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

Шаг 1: Централизация кода проверки

Для обеспечения единообразия и удобства поддержки кода, мы настоятельно рекомендуем вынести логику проверки уникальности в отдельную функцию или процедуру. Если речь идет о проверках, которые могут быть востребованы в различных модулях конфигурации, имеет смысл разместить такую функцию в Глобальном модуле. Назовем ее, например, глПроверитьУникальностьНаименованияИКПУ().

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


// Пример функции в Глобальном модуле
Функция глПроверитьУникальностьНаименованияИКПУ(Знач НаименованиеДляПроверки, Знач КодТекущегоЭлемента = "")
    Перем Результат;
    Результат = 1; // По умолчанию считаем, что наименование уникально
    
    Если ПустаяСтрока(НаименованиеДляПроверки) = 1 Тогда
        Возврат 1; // Пустые наименования считаем уникальными или обрабатываем отдельно
    КонецЕсли;
    
    Спр = СоздатьОбъект("Справочник.ИКПУ");
    Если Спр.НайтиПоНаименованию(НаименованиеДляПроверки, 1) = 1 Тогда // Найдено совпадение
        Если КодТекущегоЭлемента <> "" Тогда // Если передан код текущего элемента (для редактирования)
            Если КодТекущегоЭлемента <> Спр.Код Тогда // И найденный элемент не совпадает с текущим
                Результат = 0; // Найден дубликат
            КонецЕсли;
        Иначе // Если код текущего элемента не передан (для создания нового элемента)
            Результат = 0; // Найден дубликат
        КонецЕсли;
    КонецЕсли;
    
    Возврат Результат;
КонецФункции

Шаг 2: Использование централизованной функции

Теперь, когда у нас есть централизованная функция, мы можем вызывать ее в любом месте, где происходит программное создание или изменение элементов справочника ИКПУ. Например, при загрузке данных из Excel:


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

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

Альтернативный подход: Использование системного реквизита "Код"

В некоторых специфических случаях, если длина требуемого для уникальности поля (в нашем случае, Наименование длиной 17 символов) не превышает максимальную длину системного реквизита Код (которая в 1С 7.7 по умолчанию составляет 24 символа для строкового кода), мы можем использовать сам Код для хранения этого значения. В этом случае, мы сможем задействовать встроенный механизм контроля уникальности по Коду.

Преимущества:

  1. Встроенный контроль: Система сама не позволит создать элемент с неуникальным кодом.
  2. Простота реализации: Не требуется писать дополнительный код для проверки уникальности.

Недостатки:

  1. Ограничение по длине: Подходит только для реквизитов, чья длина не превышает 24 символа.
  2. Смысловая нагрузка: Код и Наименование – это разные сущности. Смешение их функций может привести к путанице и нарушению семантики данных, особенно если в будущем потребуется изменить логику кодирования или наименования.
  3. Тип кода: Код может быть как строковым, так и числовым. Для хранения наименования мы должны убедиться, что тип кода справочника установлен как строковый.

Для нашего случая, с наименованием в 17 символов, этот метод технически осуществим. Однако, мы рекомендуем использовать его с осторожностью и только тогда, когда это действительно оправдано и не приведет к архитектурным проблемам в будущем.


// В конфигураторе для справочника ИКПУ:
// 1. Устанавливаем тип кода: "Строковый"
// 2. Устанавливаем длину кода: минимум 17 символов (лучше с запасом, например, 24)

// В модуле формы элемента справочника:
Процедура ПриОткрытии()
    // При открытии формы, если это новый элемент, можно сразу
    // предложить ввести наименование в поле Код.
    // Если Наименование не используется, его можно скрыть или использовать для другого.
КонецПроцедуры

Процедура ПриЗаписи()
    // Если наименование хранится в коде, можно дополнительно синхронизировать
    // системное Наименование, если оно используется для представлений.
    Если ПустаяСтрока(Код) = 0 Тогда
        Наименование = Код;
    КонецЕсли;
КонецПроцедуры

В этом случае, пользователь будет вводить требуемое "наименование" в поле "Код" формы элемента справочника, а система 1С 7.7 автоматически проконтролирует его уникальность. Если поле "Наименование" по-прежнему нужно для других целей (например, для вывода в отчетах как основное представление), можно синхронизировать его значение с "Кодом" в процедуре ПриЗаписи().

Дополнительные рекомендации и анализ ситуации

  1. Производительность: Для очень больших справочников (десятки и сотни тысяч элементов) метод НайтиПоНаименованию() может быть относительно медленным, поскольку он может потребовать полного перебора элементов или сканирования индекса, если он не оптимален. В 1С 7.7 возможности по управлению индексами для строковых реквизитов ограничены. Однако для большинства типовых задач с умеренным количеством элементов (до нескольких десятков тысяч) производительности будет вполне достаточно.
  2. Регистронезависимый поиск: Метод НайтиПоНаименованию() в 1С 7.7 по умолчанию является регистрозависимым. Это означает, что "Наименование1" и "наименование1" будут считаться разными. Если вам требуется регистронезависимый контроль уникальности, вам придется сначала привести оба значения (и искомое, и значения в справочнике) к одному регистру (например, с помощью функции ВРег() или НРег()) перед сравнением. Однако НайтиПоНаименованию() не поддерживает передачу значения в измененном регистре для поиска. Поэтому для регистронезависимого контроля уникальности придется использовать более сложный механизм с обходом справочника и сравнением через ВРег(Спр.Наименование). Но для большинства бизнес-задач регистрозависимость НайтиПоНаименованию() является приемлемой.
  3. Пользовательский опыт: Важно, чтобы сообщения об ошибках были понятными и информативными для пользователя. Избегайте технических формулировок и четко указывайте, какое поле является неуникальным и почему запись невозможна.

В заключение, хоть 1С:Предприятие 7.7 и не обладает встроенным функционалом контроля уникальности для всех реквизитов, мы с вами убедились, что реализовать его программно не составляет большого труда. Используя процедуру ПриЗаписи() для интерактивного ввода и централизованную функцию для программных операций, мы можем обеспечить высокий уровень целостности данных в нашей информационной системе.

← На главную