При разработке на платформе 1С:Предприятие 8.3, особенно при использовании Библиотеки Стандартных Подсистем (БСП), разработчики часто сталкиваются с необходимостью программной установки отборов в динамических списках. Типичная ситуация: мы получаем список некоторых ссылок (например, сотрудников или документов) на сервере и хотим ограничить ими отображение данных в форме. Однако при попытке передать результат запроса напрямую в параметры отбора часто возникает критическая ошибка: «Ошибка преобразования данных XDTO: Отсутствует отображение для типа ValueTable». Рассмотрим подробнее, почему это происходит и как правильно решить данную задачу.
Для начала разберем механизм работы динамического списка. Несмотря на то, что формирование данных происходит на стороне сервера базы данных, настройки этого списка (компоновщик настроек) постоянно синхронизируются между сервером и клиентом. Это необходимо для того, чтобы пользователь мог интерактивно изменять настройки, видеть текущие отборы и управлять ими.
Когда мы выполняем код в процедуре ПриСозданииНаСервере, платформа пытается упаковать все данные формы в пакет для передачи на сторону клиента. В этот пакет попадают и настройки динамического списка. Ошибка возникает из-за того, что объект типа ТаблицаЗначений (ValueTable) не является сериализуемым для передачи между сервером и тонким клиентом в контексте настроек компоновки данных. Система XDTO (XML Data Transfer Objects), отвечающая за передачу данных, просто «не знает», как отобразить таблицу значений в структуру, доступную на клиенте внутри элемента отбора.
Проанализируем ситуацию: в коде автора переменная СписокПремированных содержит результат функции РасчетПремии.ПолучитьСписокСотрудников, которая возвращает таблицу значений. Передавая эту таблицу в качестве правого значения отбора, мы нарушаем правила типизации платформы.
Чтобы избежать ошибки, нам необходимо преобразовать таблицу значений в тип данных, который поддерживается механизмом компоновки данных и может быть передан на клиент. Наиболее подходящими типами являются Массив или СписокЗначений.
Рассмотрим по шагам, как изменить код. Если нам нужно передать колонку «Сотрудник» из полученной таблицы, мы воспользуемся методом ВыгрузитьКолонку().
Пример исправленного кода:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если ЗначениеЗаполнено(Параметры.Подразделение) Тогда
// Получаем таблицу значений с сотрудниками
ТаблицаСотрудников = РасчетПремии.ПолучитьСписокСотрудников(Параметры.Подразделение, Параметры.Период);
// Преобразуем колонку таблицы в массив (этот тип допустим для XDTO)
МассивСотрудников = ТаблицаСотрудников.ВыгрузитьКолонку("Сотрудник");
// Используем стандартную функцию БСП для установки отбора
ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка(
Список, // Имя реквизита формы (ДинамическийСписок)
"Ссылка", // Имя поля в списке, по которому делаем отбор
МассивСотрудников, // Правое значение (теперь это массив!)
ВидСравненияКомпоновкиДанных.ВСписке, // Вид сравнения
"Отбор по списку премированных", // Представление отбора
Истина, // Использование
РежимОтображенияЭлементаНастройкиКомпоновкиДанных.Обычный
);
КонецЕсли;
КонецПроцедуры
В данном примере мы заменили передачу всей таблицы на выгрузку одной конкретной колонки в массив. Массив — это универсальный тип, который прекрасно сериализуется и принимается динамическим списком при виде сравнения ВСписке.
Стоит отдельно отметить использование метода ОбщегоНазначенияКлиентСервер.УстановитьЭлементОтбораДинамическогоСписка. Это рекомендуемый способ работы в конфигурациях на базе БСП. Выясним преимущества этого метода:
Список.Отбор.Элементы и перебирать их в поисках нужного поля.В некоторых случаях, если список значений очень велик (тысячи элементов), использование визуального отбора через компоновку может привести к снижению производительности. В такой ситуации эффективнее использовать параметры самого запроса динамического списка. Разберем, как это реализовать.
Сначала в тексте запроса динамического списка (в конфигураторе) нужно добавить условие:
ГДЕ
Сотрудник В (&СписокСотрудников) ИЛИ НЕ &ИспользоватьФильтр
Затем в коде формы установим значения параметров:
&НаСервере
Процедура УстановитьФильтрЧерезПараметры(МассивСотрудников)
// Устанавливаем массив как параметр запроса
Список.Параметры.УстановитьЗначениеПараметра("СписокСотрудников", МассивСотрудников);
// Включаем или выключаем логику фильтрации в запросе
Список.Параметры.УстановитьЗначениеПараметра("ИспользоватьФильтр", МассивСотрудников.Количество() > 0);
КонецПроцедуры
Этот способ работает быстрее, так как условие обрабатывается непосредственно СУБД на этапе выполнения запроса, а не накладывается «поверх» уже полученных данных механизмом компоновки. Однако помните, что такой отбор пользователь не сможет увидеть или отключить через стандартную кнопку «Настроить список».
В исходном сообщении темы упоминалось использование УстановитьПривилегированныйРежим(Истина). Важно понимать: привилегированный режим влияет исключительно на проверку прав доступа (RLS) в базе данных. Он помогает выполнить запрос к данным, к которым у пользователя нет прямого доступа, но он никак не влияет на возможность передачи типов данных между сервером и клиентом. Ошибка XDTO возникает на уровне транспортного уровня платформы, и никакие права доступа не позволят передать ТаблицуЗначений туда, где она не поддерживается архитектурно.
Проанализировав ситуацию, мы можем сформулировать основные правила установки программных отборов:
ТаблицаЗначений или РезультатЗапроса в настройки компоновщика (отборы) динамического списка."Ссылка") точно соответствовали именам полей в схеме компоновки данных вашего списка.Соблюдение этих простых правил позволит избежать ошибок сериализации и обеспечит корректную работу пользовательского интерфейса в управляемом приложении.