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