Как правильно заполнить табличную часть документа данными из справочника с помощью запроса?

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

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

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

Рассмотрим ситуацию: при изменении реквизита «Контрагент» вызывается серверная процедура, в которую передаются данные. Часто ошибкой становится передача всей коллекции табличной части вместо ссылки на объект. Проанализируем фрагмент ошибочного кода:


&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
    // ОШИБКА: передается коллекция ТЧ, а не ссылка на контрагента
    КонтрагентПриИзмененииНаСервере(Объект.УслугиКонтрагента);
КонецПроцедуры

В результате платформа выдает ошибку: «Неверные параметры в операции сравнения. Нельзя сравнивать поля неограниченной длины и поля несовместимых типов». Это происходит потому, что в параметрах запроса в условии ГДЕ Ссылка = &Ссылка ожидается ссылка на справочник (СправочникСсылка.Контрагенты), а фактически передается объект ДанныеФормыКоллекция (табличная часть). Система управления базами данных (СУБД) не умеет сравнивать уникальный идентификатор записи с целой таблицей данных.

Правильная реализация заполнения через запрос

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

Шаг 1. Обработка события на клиенте. Мы должны взять значение из реквизита шапки документа и передать его на сервер:


&НаКлиенте
Процедура КонтрагентПриИзменении(Элемент)
    // Передаем ссылку на выбранного контрагента
    Если ЗначениеЗаполнено(Объект.Контрагент) Тогда
        КонтрагентПриИзмененииНаСервере(Объект.Контрагент);
    Иначе
        Объект.УслугиКонтрагента.Очистить();
    КонецЕсли;
КонецПроцедуры

Шаг 2. Выполнение запроса и загрузка данных на сервере. Проанализируем серверную процедуру. Использование метода Загрузить() — это самый быстрый способ заполнить табличную часть, если имена колонок в результате запроса совпадают с именами реквизитов ТЧ.


&НаСервере
Процедура КонтрагентПриИзмененииНаСервере(СсылкаНаКонтрагента)
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    Контрагенты.Услуга КАК Услуга,
        |    Контрагенты.Цена КАК Цена
        |ИЗ
        |    Справочник.Контрагенты КАК Контрагенты
        |ГДЕ
        |    Контрагенты.Ссылка = &СсылкаНаКонтрагента";
    
    Запрос.УстановитьПараметр("СсылкаНаКонтрагента", СсылкаНаКонтрагента);
    
    РезультатЗапроса = Запрос.Выполнить();
    
    // Выгружаем результат запроса в таблицу значений
    ТаблицаДанных = РезультатЗапроса.Выгрузить();
    
    // Очищаем текущую ТЧ документа перед заполнением
    Объект.УслугиКонтрагента.Очистить();
    
    // Загружаем данные. Важно: имена колонок в ТаблицаДанных 
    // должны совпадать с именами реквизитов ТЧ документа.
    Объект.УслугиКонтрагента.Загрузить(ТаблицаДанных);
    
КонецПроцедуры

Важные нюансы использования метода Загрузить()

Метод Загрузить() очень эффективен, но требует строгого соблюдения правил:

  1. Соответствие имен: Если в табличной части реквизит называется Номенклатура, а в запросе вы выбрали поле Услуга, данные не попадут в ТЧ. Всегда используйте псевдонимы в запросе (конструкция КАК), чтобы сопоставить поля.
  2. Типы данных: Типы значений в колонках таблицы значений должны соответствовать типам реквизитов табличной части.
  3. Полная перезапись: Метод Загрузить() полностью удаляет все старые строки в табличной части и заменяет их новыми. Если вам нужно просто добавить строки к существующим, этот метод не подойдет.

Альтернативный метод: Заполнение в цикле

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


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

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

Метод ЗаполнитьЗначенияСвойств() значительно упрощает код, автоматически копируя данные из полей выборки в одноименные реквизиты новой строки табличной части.

Оптимизация: работа через контекст формы

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


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

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

Резюме

Для успешного заполнения табличной части запросом необходимо:

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

← На главную