Как реализовать поиск по конкретной колонке и настроить проверку уникальности реквизита в 1С

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

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

Организация поиска по конкретной колонке динамического списка

Штатная строка поиска динамического списка производит поиск сразу по всем отображаемым колонкам. За её отображение отвечает свойство ПоложениеСтрокиПоиска таблицы динамического списка. Кроме того, пользователь может нажать сочетание клавиш Alt+F или Ctrl+F, предварительно встав на нужную колонку. Однако если требуется предоставить пользователю отдельное, постоянно видимое поле для отбора только по одной целевой колонке (например, FIN), разберем практические способы реализации.

Способ 1. Программный отбор через поле ввода

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


&НаКлиенте
Процедура ПоискFINПриИзменении(Элемент)
    УстановитьОтборПоКолонкеFIN(ПоискFIN);
КонецПроцедуры

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

Способ 2. Использование параметров произвольного запроса

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


ГДЕ
    (&ПоискFIN = "" ИЛИ Таблица.FIN ПОДОБНО "%" + &ПоискFIN + "%")

В этом случае при изменении значения в поле ввода достаточно передавать значение в параметры списка через метод Список.Параметры.УстановитьЗначениеПараметра("ПоискFIN", СокрЛП(ПоискFIN)).

Контроль уникальности реквизита при вводе

Платформа 1С предоставляет типовой флаг Контроль уникальности только для стандартных реквизитов Код и Номер. Для произвольного реквизита объекта (такого как FIN) этот флаг недоступен. Выясним, какими способами можно предотвратить появление дубликатов.

Выделим основные архитектурные подходы:

  1. Использование стандартного кода: Если значение является основным идентификатором сущности, откажемся от отдельного реквизита и используем стандартный реквизит Код с типом Строка, включив штатное свойство Контроль уникальности.
  2. Перенос данных в регистр сведений: Если данные хранятся в регистре сведений, назначим поле FIN измерением регистра. Платформа физически не позволит создать записи с совпадающими ключевыми измерениями.
  3. Программный контроль перед записью: Если FIN должен оставаться дополнительным реквизитом справочника или документа, выполним проверку в событии ПередЗаписью модуля объекта.

Разберем подробнее программную проверку в модуле объекта с учетом многопользовательского режима. Проанализируем типовые ошибки при такой реализации: во-первых, нельзя забывать об исключении текущей ссылки (иначе при повторном сохранении уже существующего элемента платформа сочтет его дублем самого себя); во-вторых, для предотвращения одновременной записи одинаковых значений разными пользователями необходимо устанавливать управляемую блокировку.

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


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

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

← На главную