При разработке на обычных формах в 1С часто возникает задача: перехватить событие изменения периода в форме списка документов (например, в списке «Реализация товаров и услуг»). Цель — проверить условия и, при необходимости, отказаться от применения выбранного отбора, чтобы не допустить формирования слишком тяжелых запросов. Рассмотрим, с какими ограничениями платформы мы сталкиваемся и как правильно решить эту задачу.
Проанализируем ситуацию. В обычных формах платформа 1С не предоставляет штатных событий, которые позволили бы перехватить нажатие стандартной кнопки настройки периода с возможностью отмены (отсутствует параметр Отказ). События табличного поля и самого объекта ДокументСписок не реагируют на вызов стандартного диалогового окна выбора периода до того момента, пока пользователь не нажмет «ОК» и отбор не будет фактически применен к списку. В обновлении отображения проверять период и пытаться от него отказаться уже поздно — запрос к базе данных уже ушел.
Если для отбора используется вид сравнения «В списке» с передачей массива из тысяч ссылок на документы (например, полученных отдельным запросом по сложным условиям), это считается жестким антипаттерном. Выясним причину: на уровне системы управления базами данных (СУБД) такой отбор преобразуется в конструкцию IN (...) с огромным количеством параметров. Это вызывает сильную деградацию производительности, длительный поиск, блокировки, а при превышении внутренних лимитов SQL-сервера на количество параметров в запросе форма может аварийно завершить работу.
Разберем по шагам единственный рабочий способ контролировать вводимый период. Нам потребуется полностью отключить стандартную кнопку и заменить ее на программную реализацию.
ВвестиПериод() для вызова диалога выбора дат.ДокументСписок.Отбор.Дата.Установить(). Если интервал слишком большой, выведем предупреждение и прервем выполнение.Посмотрим на пример реализации обработчика нажатия нашей кнопки:
Процедура ДействиеУстановитьПериод(Кнопка)
НачалоПериода = ДокументСписок.Отбор.Дата.ЗначениеС;
КонецПериода = ДокументСписок.Отбор.Дата.ЗначениеПо;
Если ВвестиПериод(НачалоПериода, КонецПериода, "Выберите период") Тогда
// Проверяем, что период не больше 31 дня
Если (КонецПериода - НачалоПериода) > 31 * 24 * 60 * 60 Тогда
Предупреждение("Выбран слишком большой период! Пожалуйста, выберите интервал не более месяца.");
Возврат;
КонецЕсли;
// Устанавливаем отбор
ДокументСписок.Отбор.Дата.Использование = Истина;
ДокументСписок.Отбор.Дата.ВидСравнения = ВидСравнения.ИнтервалВключаяГраницы;
ДокументСписок.Отбор.Дата.ЗначениеС = НачалоПериода;
ДокументСписок.Отбор.Дата.ЗначениеПо = КонецПериода;
КонецЕсли;
КонецПроцедуры
Если изначальная проблема заключается в необходимости фильтровать список по сложному условию (например, по дополнительному свойству контрагента в документе), рассмотрим более оптимальные архитектурные решения, не требующие подстановки массива ссылок в отбор.
1. Использование Критериев отбора
Если дополнительное свойство можно типизировать и привязать к реквизитам документов, создайте объект метаданных «Критерий отбора». Формы списков в 1С умеют штатно и быстро фильтроваться по критериям отбора. Платформа сама сгенерирует оптимальный запрос без необходимости программно собирать массивы.
2. Использование Построителя отчета
Вместо стандартного объекта ДокументСписок поместите на форму обычное Табличное поле, а его данные заполняйте через объект ПостроительОтчета. В тексте запроса построителя можно прописать любые левые соединения с таблицами свойств, регистров сведений и справочников. Построитель автоматически сгенерирует настройки отбора (которые можно вывести пользователю на форму) и выполнит оптимальный запрос к базе данных.
3. Денормализация данных
Если по определенному реквизиту или свойству отбор требуется постоянно и для всех пользователей, добавьте этот реквизит непосредственно в шапку документа и установите для него признак «Индексировать». Это потребует изменения метаданных и создания подписки на событие (или обработки при записи) для синхронизации значения. Однако это позволит использовать стандартный, очень быстрый отбор по реквизиту без жестких ограничений по периоду, так как СУБД будет использовать индекс.
4. Использование Таблицы значений
Если период всегда жестко ограничен (например, пользователи никогда не смотрят документы более чем за текущий месяц), список можно получать собственным сложным запросом с нужными соединениями и выгружать в Таблицу Значений, которая будет источником данных для табличного поля на форме. Для имитации стандартного поведения платформы, в обработчики ПриВыводеСтроки или ПриПолученииДанных добавляется код для отображения стандартных пиктограмм (статус проведения, пометка удаления и т.д.).