Как в 1С организовать выбор нескольких значений и передать их в запрос?

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

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

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

Анализ исходного кода и ключевые ошибки

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

  1. Неверный тип реквизита формы. На форме был создан реквизит ОтборМодель с типом СправочникСсылка.уатМоделиТС. Этот тип данных предназначен для хранения одной ссылки на конкретный элемент справочника. Он физически не может содержать в себе несколько ссылок или строку с их перечислением.
  2. Получение наименований вместо ссылок. В серверной функции МаркиТС() запрос выбирает ссылки и наименования, но в список значений загружается только колонка с наименованиями: Список.ЗагрузитьЗначения(РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Наименование")). В итоге форма выбора оперирует не ссылками на объекты, а просто их текстовыми представлениями. Это вторая фундаментальная ошибка.
  3. Формирование строки. Клиентский код перебирает отмеченные элементы и формирует из них единую строку через запятую: МодельСтрока = МодельСтрока + ЭлементСписка.Значение + ", ".
  4. Финальная ошибка присваивания. Строка, полученная на предыдущем шаге, делается попытка присвоить реквизиту Отчет.ОтборМодель, который, как мы помним, имеет тип СправочникСсылка. Это и есть причина, по которой "значения не летят в поле ввода". Платформа не может преобразовать строку "Модель А, Модель Б, " в ссылку на один конкретный объект.

Теперь, когда мы выяснили причины, рассмотрим несколько правильных способов решения этой задачи.

Решение 1. Использование реквизита с типом "СписокЗначений"

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

Шаг 1. Создаем правильные реквизиты на форме.

Нам понадобятся два реквизита:

Шаг 2. Корректируем серверную функцию.

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


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

Шаг 3. Модифицируем клиентскую процедуру выбора.

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


&НаКлиенте
Процедура ОтборМодельНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    СтандартнаяОбработка = Ложь;
	
    // Получаем с сервера список моделей со ссылками
    СписокДляВыбора = ПолучитьСписокМоделей();
	
    // Устанавливаем пометки для уже выбранных ранее элементов
    Для Каждого ЭлементСписка Из СписокДляВыбора Цикл
        Если СписокМоделей.НайтиПоЗначению(ЭлементСписка.Значение) <> Неопределено Тогда
            ЭлементСписка.Пометка = Истина;
        КонецЕсли;
    КонецЦикла;
	
    // Открываем стандартный диалог выбора из списка
    ВыбранныеЭлементы = СписокДляВыбора.ОтметитьЭлементы("Выберите модели транспортных средств:");
	
    // Если пользователь что-то выбрал и нажал "ОК"
    Если ВыбранныеЭлементы <> Неопределено Тогда
        // Очищаем старые значения
        СписокМоделей.Очистить();
        МассивПредставлений = Новый Массив;
		
        // Заполняем реквизиты новыми данными
        Для Каждого ВыбранныйЭлемент Из ВыбранныеЭлементы Цикл
            СписокМоделей.Добавить(ВыбранныйЭлемент.Значение); // Добавляем ССЫЛКУ в список
            МассивПредставлений.Добавить(ВыбранныйЭлемент.Представление); // Добавляем НАИМЕНОВАНИЕ в массив для отображения
        КонецЦикла;
		
        // Формируем красивую строку для пользователя
        ПредставлениеМоделей = СтрСоединить(МассивПредставлений, ", ");
    КонецЕсли;
	
КонецПроцедуры

Шаг 4. Используем результат в запросе.

Самое главное — теперь у нас есть реквизит СписокМоделей, который можно напрямую передать в параметр запроса с условием В СПИСКЕ.


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

Этот подход является наиболее чистым и эффективным. Он разделяет хранение данных (ссылок) и их отображение (строку), что соответствует лучшим практикам разработки на платформе 1С.

Решение 2. Стандартный отбор "В списке" для отчетов на СКД

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

Что нужно сделать:

  1. Убедитесь, что в схеме компоновки данных для поля "Модель" на закладке "Настройки" включен флажок "Включать в пользовательские настройки".
  2. Когда пользователь откроет настройки отчета, он сможет сам добавить новый элемент отбора по полю "Модель".
  3. В колонке "Вид сравнения" он сможет выбрать стандартный вариант "В списке".
  4. Платформа автоматически предоставит ему удобную форму для выбора нескольких значений из справочника.

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

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

← На главную