В процессе разработки в среде «1С:Предприятие» на обычных формах программисты часто сталкиваются с аппаратным ограничением платформы при работе с элементом управления ДокументСписок (или ЖурналДокументовСписок). Стандартный механизм отборов в обычных формах связывает все добавляемые поля исключительно по логическому условию «И». Но что делать, если перед нами стоит задача отобразить документы, в которых заданная касса пользователя может быть как кассой-отправителем (реквизит Касса), так и кассой-получателем (реквизит КассаПолучатель)?
В рамках этой статьи мы подробно разберем пять практических методов решения этой задачи, проанализируем их плюсы, минусы и особенности реализации.
Это наиболее нативный, быстрый и производительный метод, предусмотренный самой платформой «1С:Предприятие» для обхода ограничения логического «ИЛИ».
Разберем по шагам, как настроить этот механизм в конфигураторе:
ДокументыПоКассе).СправочникСсылка.Кассы.ВнутреннееПеремещениеНаличныхДенежныхСредств и отмечаем реквизиты Касса и КассаПолучатель.Как это работает на уровне СУБД? Платформа автоматически сформирует оптимизированный поисковый запрос к базе данных, связав выбранные реквизиты по условию «ИЛИ» с использованием существующих индексов. Чтобы вывести этот список пользователю, достаточно программно открыть форму критерия отбора, передав туда в качестве параметра текущую основную кассу пользователя.
Если конфигурация работает в режиме совместимости, позволяющем использовать управляемые формы в обычном приложении, мы можем заменить стандартную обычную форму списка документов на управляемую.
В управляемых формах за вывод списков отвечает объект ДинамическийСписок, работающий на базе системы компоновки данных (СКД). СКД без проблем поддерживает группировку условий отбора по логическому «ИЛИ».
Рассмотрим пример программной настройки такого отбора при создании формы на сервере:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Получаем основную кассу текущего пользователя
ОсновнаяКасса = ГлобальныйМодульКлиентСервер.ПолучитьОсновнуюКассуПользователя();
// Очищаем стандартные отборы динамического списка, если это необходимо
Список.Отбор.Элементы.Очистить();
// Создаем группу «ИЛИ» для объединения условий
ГруппаИЛИ = Список.Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
ГруппаИЛИ.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаИли;
ГруппаИЛИ.Использование = Истина;
// Добавляем первое условие: проверка по кассе-отправителю
ЭлементОтбора1 = ГруппаИЛИ.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора1.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("Касса");
ЭлементОтбора1.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора1.ПравоеЗначение = ОсновнаяКасса;
ЭлементОтбора1.Использование = Истина;
// Добавляем второе условие: проверка по кассе-получателю
ЭлементОтбора2 = ГруппаИЛИ.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора2.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("КассаПолучатель");
ЭлементОтбора2.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
ЭлементОтбора2.ПравоеЗначение = ОсновнаяКасса;
ЭлементОтбора2.Использование = Истина;
КонецПроцедуры
Этот способ является наиболее гибким, так как позволяет динамически изменять условия прямо в пользовательском интерфейсе.
На форумах часто критикуют подход, при котором сначала запросом выбираются нужные документы, а затем их массив передается в отбор списка с видом сравнения ВидСравнения.ВСписке. Основной аргумент против — низкая производительность при росте базы данных.
Однако этот метод вполне жизнеспособен, если внедрить в него обязательные правила оптимизации:
ПЕРВЫЕ N в тексте запроса, чтобы не перегружать оперативную память клиента, если документов окажется слишком много.Касса и КассаПолучатель в свойствах метаданных документа установлено значение «Индексировать» или «Индексировать с дополнительным упорядочиванием». Без индексов СУБД будет выполнять полное сканирование таблицы (Table Scan), что приведет к сильным зависаниям.Проанализируем пример реализации такого подхода в модуле обычной формы списка:
Процедура УстановитьОтборПоКассам()
ОсновнаяКасса = ПолучитьОсновнуюКассуПользователя();
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1000
| Док.Ссылка КАК Ссылка
|ИЗ
| Документ.ВнутреннееПеремещениеНаличныхДенежныхСредств КАК Док
|ГДЕ
| Док.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И (Док.Касса = &ОсновнаяКасса ИЛИ Док.КассаПолучатель = &ОсновнаяКасса)";
Запрос.УстановитьПараметр("ОсновнаяКасса", ОсновнаяКасса);
// Ограничиваем выборку последними 3 месяцами для быстродействия
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДобавитьМесяц(ТекущаяДата(), -3)));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ТекущаяДата()));
ТаблицаРезультата = Запрос.Выполнить().Выгрузить();
МассивСсылок = ТаблицаРезультата.ВыгрузитьКолонку("Ссылка");
// Применяем отбор к стандартному списку документов обычной формы
ОтборСсылка = ДокументСписок.Отбор.Ссылка;
ОтборСсылка.ВидСравнения = ВидСравнения.ВСписке;
ОтборСсылка.Значение.Очистить();
Для Каждого Ссылка Из МассивСсылок Цикл
ОтборСсылка.Значение.Добавить(Ссылка);
КонецЦикла;
ОтборСсылка.Использование = Истина;
КонецПроцедуры
Для крупных высоконагруженных систем отличным архитектурным решением станет денормализация данных с использованием вспомогательного регистра.
Разберем алгоритм его проектирования:
СвязиДокументовИКасс.Касса (тип СправочникСсылка.Кассы) и Документ (тип ДокументСсылка.ВнутреннееПеремещениеНаличныхДенежныхСредств).Касса является проиндексированным измерением.Механизм RLS (Row Level Security) часто упоминается как самый надежный способ решения подобных задач, особенно если цель заключается в физическом сокрытии данных от пользователя из соображений безопасности.
Однако при использовании RLS для отбора по «ИЛИ» нужно учитывать критически важные нюансы:
ГДЕ ваши условия. Конструкции с «ИЛИ» в правилах RLS часто заставляют оптимизатор СУБД отказываться от использования индексов. В результате при росте базы данных пользователи могут столкнуться с заметными задержками при открытии журналов документов.Таким образом, использовать RLS следует исключительно в тех случаях, когда это обусловлено жесткими требованиями информационной безопасности компании, а не просто желанием отфильтровать интерфейс для удобства пользователя.