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