Как исправить ошибку «Отсутствует отображение для типа СправочникВыборка» при объектном чтении данных в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с задачей программного заполнения списков выбора или получения данных из справочников без использования запросов. Одним из классических способов является использование объектной модели, а именно метода Выбрать(). Однако при попытке передать результат этого метода с сервера на тонкий клиент возникает ошибка: «Ошибка отображения типов: Отсутствует отображение для типа СправочникВыборка». В этой статье мы подробно разберем, почему возникает эта ошибка, как правильно организовать передачу данных и какие альтернативные способы существуют для решения этой задачи.

Почему возникает ошибка при передаче выборки?

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

Тонкий клиент — это среда, которая не имеет прямого доступа к базе данных. Передача данных между сервером и тонким клиентом происходит посредством сериализации (преобразования объекта в поток байтов, обычно XML или JSON). Платформа 1С умеет сериализовать универсальные коллекции, такие как Массив, Структура, СписокЗначений или ТаблицаЗначений (с определенными оговорками). Однако объект СправочникВыборка является специализированным серверным объектом, который не предназначен для сериализации. Он жестко привязан к контексту сервера и соединению с СУБД.

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

Решение проблемы через промежуточный массив

Рассмотрим самый простой и надежный способ решения задачи в рамках объектной модели. Нам необходимо на стороне сервера обойти выборку в цикле, поместить нужные нам данные (ссылки) в массив и вернуть этот массив на клиент.

Разберем по шагам реализацию серверной функции:


&НаСервереБезКонтекста
Функция ПолучитьМассивНоменклатуры()
    
    // Инициализируем выборку на сервере
    Выборка = Справочники.Номенклатура.Выбрать();
    
    // Создаем массив — эту коллекцию платформа умеет передавать на клиент
    Результат = Новый Массив;
    
    // Обходим выборку и заполняем массив ссылками
    Пока Выборка.Следующий() Цикл
        Результат.Добавить(Выборка.Ссылка);
    КонецЦикла;
    
    Возврат Результат;
    
КонецФункции

Теперь посмотрим, как использовать эти данные в обработчике события НачалоВыбора на форме элемента. Нам нужно подменить стандартное поведение платформы и вывести свой список значений.


&НаКлиенте
Процедура НоменклатураНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    // Отключаем стандартное открытие формы выбора
    СтандартнаяОбработка = Ложь;
    
    // Получаем массив ссылок с сервера
    МассивСсылок = ПолучитьМассивНоменклатуры();
    
    // Создаем список значений для отображения пользователю
    СписокВыбора = Новый СписокЗначений;
    СписокВыбора.ЗагрузитьЗначения(МассивСсылок);
    
    // Выводим список пользователю для выбора
    ВыбранныйЭлемент = ПоказатьВыборИзСписка(СписокВыбора, Элемент);
    
КонецПроцедуры

Оптимизация: Массив или СписокЗначений?

Проанализируем технический нюанс, затронутый в обсуждении: что лучше передавать между сервером и клиентом — Массив или СписокЗначений? С точки зрения производительности, Массив является более легким объектом. Он содержит только значения. СписокЗначений — это гораздо более сложная структура, которая включает в себя пометки, представления, картинки и дополнительные данные. Сериализация тяжелого списка значений требует больше ресурсов процессора и создает большую нагрузку на сеть.

Рекомендация: если вам нужно просто передать набор ссылок, используйте Массив. Преобразовать его в СписокЗначений на стороне клиента с помощью метода ЗагрузитьЗначения() — операция мгновенная.

Почему использование объектной модели (.Выбрать) — не лучший вариант?

Хотя в учебных задачах часто требуют использовать именно Выбрать(), в реальной промышленной разработке это считается плохим тоном (anti-pattern) по нескольким причинам:

  1. Избыточность данных. Метод Выбрать() всегда считывает из базы данных абсолютно все поля объекта. Если в справочнике «Номенклатура» 50 реквизитов и несколько табличных частей, система прочитает их все, даже если вам нужна только ссылка.
  2. Производительность. Запрос к базе данных выполняется на уровне СУБД значительно быстрее. Вы можете выбрать только поле Ссылка, что сэкономит память сервера и сократит время выполнения.
  3. Сложные отборы. Метод Выбрать() поддерживает только простейшие фильтры по равенству. В запросе же вы можете использовать условия «ИЛИ», вхождение в массив, сравнения «Больше/Меньше» и другие возможности языка SQL.

Посмотрим на пример того, как та же задача решается через запрос. Это более «взрослый» и правильный подход:


&НаСервереБезКонтекста
Функция ПолучитьМассивНоменклатурыЗапросом()
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Номенклатура.Ссылка КАК Ссылка
        |ИЗ
        |   Справочник.Номенклатура КАК Номенклатура";
    
    РезультатЗапроса = Запрос.Выполнить();
    
    // Используем метод выгрузки колонки, чтобы получить массив в одну строку
    Возврат РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Ссылка");
    
КонецФункции

Современный подход: ОбработкаПолученияДанныхВыбора

Если ваша задача — не просто разово вывести список в коде, а настроить поведение поля ввода так, чтобы оно предлагало определенные элементы при наборе текста или нажатии на кнопку выбора, лучше всего использовать механизм ОбработкаПолученияДанныхВыбора в модуле менеджера справочника.

Этот метод работает на стороне сервера и позволяет динамически формировать список ДанныеВыбора. Рассмотрим преимущества этого подхода:

Пример кода в модуле менеджера справочника «Номенклатура»:


Процедура ОбработкаПолученияДанныхВыбора(ДанныеВыбора, Параметры, СтандартнаяОбработка)
    
    // Если нам нужно реализовать свою логику, отключаем стандартную
    СтандартнаяОбработка = Ложь;
    
    СписокЗначений = Новый СписокЗначений;
    
    // Здесь можно использовать либо объектную выборку, либо запрос
    Выборка = Справочники.Номенклатура.Выбрать();
    Пока Выборка.Следующий() Цикл
        СписокЗначений.Добавить(Выборка.Ссылка, Выборка.Наименование);
    КонецЦикла;
    
    ДанныеВыбора = СписокЗначений;
    
КонецПроцедуры

Подведем итоги

Мы выяснили, что ошибка «Отсутствует отображение для типа СправочникВыборка» является следствием попытки передать чисто серверный объект на тонкий клиент. Чтобы решить эту проблему, необходимо:

  1. Выполнять обход выборки на стороне сервера внутри функции с директивой &НаСервере или &НаСервереБезКонтекста.
  2. Переносить данные из выборки в универсальную коллекцию (рекомендуется Массив).
  3. Возвращать массив на клиент и там загружать его в нужный элемент управления.

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

← На главную