Механизм динамических списков в платформе 1С:Предприятие 8 является одним из самых мощных инструментов для отображения табличных данных. Однако стандартная генерация запроса не всегда покрывает сложные требования бизнеса, когда необходимо объединять данные из нескольких таблиц или применять специфическую фильтрацию до вывода на экран.

Процесс перехвата логики формирования набора данных требует глубокого понимания архитектуры клиента-серверного взаимодействия. Разработчики часто сталкиваются с ситуацией, когда стандартный конструктор не позволяет задать нужные JOIN-ы или группировки, что делает переопределение запроса единственным верным решением для оптимизации производительности и гибкости интерфейса.

В данной статье мы детально разберем алгоритм действий: от создания серверного обработчика до написания сложной логики выборки. Вы узнаете, как корректно внедрить свой код, не нарушив стандартные механизмы платформы, и избежите типичных ошибок, приводящих к потере управляемости списком.

Архитектура динамических списков и точка расширения

Динамический список представляет собой объект метаданных, который автоматически генерирует запрос на основе настроек полей и отборов. Но у этого механизма есть "точка входа", позволяющая полностью подменить системный запрос на пользовательский. Это событие называется ПриЧтенииНаСервере.

Именно в этом обработчике происходит магия подмены. Если вы установите свойство ИспользоватьIfExists (или аналогичный флаг в зависимости от версии платформы) в истину, система проигнорирует стандартную логику построения запроса. Вместо этого она выполнит код, который вы напишете в модуле формы или модуле менеджера объекта.

Важно понимать разницу между клиентским и серверным контекстом. Запрос формируется исключительно на стороне сервера, поэтому весь код, связанный с объектом Запрос, должен находиться в серверных процедурах. Попытка выполнить это на клиенте приведет к ошибке выполнения или непредсказуемому поведению интерфейса.

⚠️ Внимание: При переопределении запроса вы берете на себя полную ответственность за структуру возвращаемых данных. Если поля в результате запроса не будут совпадать с полями, ожидаемыми динамическим списком, интерфейс может просто не отобразить данные или выдать ошибку типизации.

Существует несколько сценариев, когда вмешательство в работу списка необходимо:

  • 🔍 Нужно выполнить соединение (JOIN) с регистром сведений, которого нет в основной таблице объекта.
  • 📊 Требуется сложная агрегация данных (суммы, количества) непосредственно в списке без использования промежуточных отчетов.
  • ⚡ Необходимо оптимизировать выборку, убрав лишние поля или добавив специфические индексы через директивы запроса.
  • 🔒 Требуется реализовать программную фильтрацию прав доступа, которую нельзя задать стандартными ролями или отборами формы.
📊 Как часто вы переопределяете запросы в 1С?
Ежедневно
Раз в неделю
Только в сложных проектах
Никогда, использую стандартные средства

Создание обработчика события ПриЧтенииНаСервере

Первым шагом является настройка самого динамического списка в конфигураторе. Откройте форму, содержащую список, и найдите в дереве элементов нужную таблицу или поле со списком. В свойствах этого элемента необходимо найти группу свойств, отвечающих за чтение данных.

В зависимости от версии конфигурации, вам может потребоваться установить флажок ИспользоватьСобытиеПриЧтении или просто выбрать событие из выпадающего списка. После этого платформа автоматически создаст заготовку процедуры в модуле формы. Название процедуры обычно имеет вид ИмяСпискаПриЧтенииНаСервере.

В сигнатуре этой процедуры вы увидите важный параметр — Запрос. Это объект типа Запрос, который уже инициализирован системой, но пока пуст или содержит стандартную структуру. Ваша задача — наполнить его текстом запроса и передать параметры.

Процедура СписокДокументовПриЧтенииНаСервере(Отказ, СтандартнаяОбработка, Запрос, ПараметрыЧтения, Выборка, ДополнительныеПараметры)

// Отключаем стандартную обработку, чтобы система не формировала свой запрос

СтандартнаяОбработка = Ложь;

ТекстЗапроса = Новый Запрос;

ТекстЗапроса.Текст =

"ВЫБРАТЬ

| ДокументыРеализацияТоваровУслуг.Ссылка КАК Ссылка,

| ДокументыРеализацияТоваровУслуг.Дата КАК Дата,

| ДокументыРеализацияТоваровУслуг.Номер КАК Номер

|ИЗ

| Документ.РеализацияТоваровУслуг КАК ДокументыРеализацияТоваровУслуг";

Запрос.Текст = ТекстЗапроса.Текст;

КонецПроцедуры

Ключевой момент здесь — присваивание значения Ложь параметру СтандартнаяОбработка. Если этого не сделать, система проигнорирует ваш запрос и выполнит стандартный, что сведет все усилия к нулю. Это самая частая ошибка новичков при работе с динамическими списками.

💡

Всегда проверяйте имена полей в запросе. Они должны точно совпадать с именами полей в настройках динамического списка, иначе данные не маппингнутся в колонки таблицы.

Формирование текста запроса и работа с параметрами

Написание текста запроса для динамического списка имеет свои особенности. В отличие от обычных отчетов, здесь критически важен порядок полей и их типы. Система динамических списков ожидает, что первое поле в выборке часто будет использоваться как ключ (обычно это Ссылка или УникальныйИдентификатор).

Для обеспечения гибкости фильтрации, которую пользователь задает через интерфейс (например, вводит дату в поле отбора), необходимо использовать параметры запроса. Динамический список автоматически подставляет значения отборов в специальные параметры, имена которых формируются по определенному правилу.

Рассмотрим таблицу соответствия параметров, которые система передает в обработчик:

Параметр процедуры Описание Пример использования
ПараметрыЧтения Структура с системными параметрами (период, владелец и т.д.) ПараметрыЧтения.Период
ДополнительныеПараметры Параметры, заданные в настройках списка вручную ДополнительныеПараметры.МойПараметр
Запрос.Параметры Коллекция параметров самого объекта запроса Запрос.Параметры.Вставить("ДатаНач", Значение)

Если в вашем запросе используются отборы, которые пользователь может менять на форме, вам нужно вручную связать их с параметрами запроса. Это делается через коллекцию Запрос.Параметры. Вы должны извлечь значение из ПараметрыЧтения или ДополнительныеПараметры и присвоить его соответствующему параметру текста запроса.

Пример установки параметра в коде:

Запрос.Параметры.Вставить("ПериодНачало", ПараметрыЧтения.Период.ДатаНачала);

Запрос.Параметры.Вставить("ПериодКонец", ПараметрыЧтения.Период.ДатаОкончания);

Такой подход позволяет сохранить интерактивность списка: пользователь меняет период в интерфейсе, а ваш код корректно подставляет новые значения в SQL-подобный запрос перед его выполнением на сервере СУБД.

Тонкости работы с виртуальными таблицами

Если вы используете срезы регистров (Периодические, Последнее), убедитесь, что параметр периода передается корректно. Ошибка в типе даты (вместо Даты передали Строку) приведет к падению запроса с ошибкой преобразования типов.

Обработка результатов и возврат выборки

После того как текст запроса сформирован и параметры установлены, необходимо выполнить выборку. Однако в обработчике ПриЧтенииНаСервере вы не возвращаете таблицу значений явно через Возврат. Вместо этого вы должны передать результат в специальный параметр Выборка.

Объект Выборка имеет тип ВыборкаИзРезультатаЗапроса. Система сама выполнит запрос, если вы не сделаете это явно, но лучшим тоном считается выполнение запроса внутри обработчика для контроля над ошибками. Результат выполнения (Запрос.Выполнить()) нужно присвоить переменной Выборка.

Если ваш запрос возвращает пустой результат, это не является ошибкой. Динамический список корректно отобразит пустую таблицу. Проблемы возникают, если структура колонок не совпадает. Например, если в настройках списка ожидается поле типа Число, а в запросе приходит Строка, возникнет исключение.

⚠️ Внимание: Никогда не пытайтесь модифицировать данные в выборке перед возвратом. Динамический список предназначен для чтения. Изменение данных должно происходить через формы документов или специальные обработки, а не на уровне списка.

Пример корректного завершения процедуры:

РезультатЗапроса = Запрос.Выполнить();

Выборка = РезультатЗапроса.Выбрать();

Также стоит упомянуть о параметре Отказ. Если в процессе формирования запроса произошла критическая ошибка или условия бизнес-логики не позволяют показывать данные (например, у пользователя нет прав), вы можете установить Отказ = Истина. В этом случае список не будет заполнен, и система может показать стандартное сообщение об ошибке или просто оставить поле пустым.

Фильтрация и отборы в переопределенном запросе

Одним из главных преимуществ переопределения является возможность реализации сложной логики отборов. Стандартные отборы динамического списка работают по принципу "И" для разных полей и "ИЛИ" для значений одного поля. Иногда бизнесу требуется логика вида: "(А И Б) ИЛИ (В И Г)".

Такую логику можно реализовать только вручную в тексте запроса. Однако возникает вопрос: как учесть пользовательские отборы, которые он уже установил в интерфейсе? Для этого нужно проанализировать структуру ПараметрыЧтения. В ней содержится информация о всех активных отборах, установленных пользователем в форме.

Вы можете программно проверить наличие определенных отборов и, в зависимости от этого, менять текст запроса или добавлять условия в секцию ГДЕ. Это дает огромную гибкость, но усложняет поддержку кода.

  • 🛠 Используйте условные конструкции Если...Тогда для добавления фрагментов текста запроса динамически.
  • 📝 Комментируйте сложные условия в запросе, чтобы другие разработчики понимали логику фильтрации.
  • 🧪 Обязательно тестируйте запрос с разными комбинациями отборов, чтобы убедиться в отсутствии конфликтов.

Если вы добавляете свои собственные параметры фильтрации, которые не являются стандартными полями объекта, их нужно объявить в свойствах динамического списка как "Дополнительные параметры". Затем они станут доступны в процедуре чтения через коллекцию ДополнительныеПараметры.

💡

Сложная логика отборов в тексте запроса повышает производительность, так как фильтрация происходит на уровне СУБД, а не клиентского приложения, что критично для больших объемов данных.

Типичные ошибки и производительность

При работе с переопределением запросов разработчики часто совершают ошибки, влияющие на скорость работы системы. Самая распространенная проблема — выполнение запросов внутри цикла или отсутствие необходимых индексов в условиях соединения таблиц.

Помните, что динамический список может перерисовываться очень часто (при изменении отборов, обновлении интерфейса). Если ваш запрос "тяжелый" и выполняется долго, интерфейс 1С "зависнет" до получения ответа от сервера. Используйте директиву РАЗРЕШЕННЫЕ_ПОЛЯ или оптимизируйте текст запроса, выбирая только необходимые колонки.

Еще одна частая ошибка — игнорирование прав доступа. Стандартный механизм динамических списков автоматически применяет RLS (Record Level Security). При переопределении запроса вы должны самостоятельно убедиться, что пользователь не увидит чужие данные. Это можно сделать, добавив проверку по организации или подразделению в условие ГДЕ.

⚠️ Внимание: Если ваша конфигурация работает в режиме предприятия с ограниченным профилем безопасности, убедитесь, что у роли пользователя есть право на чтение всех таблиц, участвующих в вашем кастомном запросе. Иначе запрос упадет с ошибкой прав доступа.

Также стоит учитывать версию платформы. В старых версиях 1С (до 8.3.10) механизм переопределения работал иначе и имел больше ограничений. Если вы поддерживаете старые релизы, обязательно сверяйтесь с документацией по конкретной версии платформы, так как синтаксис обработчиков мог меняться.

☑️ Проверка перед выпуском

Выполнено: 0 / 5

Часто задаваемые вопросы (FAQ)

Можно ли изменить запрос только для конкретного пользователя?

Да, это возможно. Внутри процедуры ПриЧтенииНаСервере вы можете получить информацию о текущем пользователе через объект ПользователиИнформационнойБазы или глобальный контекст. На основе этого вы можете формировать разные тексты запросов или устанавливать разные параметры фильтрации для разных ролей.

Почему после переопределения перестали работать стандартные отборы формы?

Скорее всего, вы не связали параметры отборов формы с параметрами вашего запроса. Стандартные отборы не подставляются в текст запроса автоматически при полном переопределении. Вам нужно вручную прочитать ПараметрыЧтения и передать их значения в Запрос.Параметры.

Как вернуть сортировку в переопределенном списке?

Сортировка задается непосредственно в тексте запроса с помощью секции УПОРЯДОЧИТЬ ПО. Динамический список respects эту директиву. Если пользователь меняет сортировку кликом по заголовку колонки, система может попытаться добавить свою сортировку поверх вашей, что иногда приводит к дублированию. Лучше явно задать сортировку в запросе и запретить пользователю менять её в настройках списка, если это критично.

Можно ли использовать временные таблицы в таком запросе?

Да, вы можете создавать временные таблицы в теле запроса, используя конструкцию ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ_Имя. Однако помните, что жизнь временной таблицы ограничена сеансом выполнения запроса. Для сложных многоступенчатых выборок это отличный способ оптимизации, но не забудьте очистить их или позволить системе сделать это автоматически после завершения процедуры.

Влияет ли переопределение запроса на экспорт данных из списка?

Да, влияет. Поскольку экспорт (в MXL, CSV, Табличный Документ) берет данные из того же набора, который отображается на экране, ваш кастомный запрос определит, что именно попадет в выгружаемый файл. Это позволяет гибко настраивать состав экспортных данных без создания отдельных отчетов.