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