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

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

В процессе разработки на платформе 1С:Предприятие 8 часто возникает задача: необходимо получить данные, которые хранятся не в основных реквизитах справочника, а в его табличной части, и перенести их в документ. Ситуация осложняется, когда работа ведется в режиме управляемых форм, где существует строгое разделение на клиентский и серверный контекст. Разберем эту задачу на примере конфигурации «Управление торговлей 10.3», где в справочнике Договоры хранится информация о ставках специалистов, которую нужно автоматически подтянуть в документ.

Разберем причину возникновения ошибки Поле объекта не обнаружено

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

Проанализируем ситуацию: в 1С ссылка (объект типа СправочникСсылка) содержит в себе только значения основных реквизитов, которые отображаются в списке (например, Код, Наименование). Табличные части не входят в состав данных ссылки. Чтобы получить к ним доступ через объектную модель, необходимо получить весь объект из базы данных в оперативную память командой ПолучитьОбъект(). Однако в управляемых формах и при работе с большими объемами данных такой подход крайне неэффективен, так как он замедляет работу системы. Правильным способом получения данных табличных частей является использование запросов.

Решение 1. Прямое соединение таблиц в запросе (Оптимальный способ)

Рассмотрим самый эффективный метод. Вместо того чтобы сначала выгружать данные из договора, а потом передавать их куда-то еще, мы можем сразу обратиться к таблице табличной части справочника внутри основного запроса, который заполняет документ. В языке запросов 1С любая табличная часть доступна как отдельная таблица с именем Справочник.[ИмяСправочника].[ИмяТабличнойЧасти].

Предположим, у нас есть запрос из сообщения №25. Нам нужно модифицировать его так, чтобы он подтягивал ставку напрямую из договора. Рассмотрим, как это сделать по шагам:

  1. Определим имя табличной части в метаданных (например, Ставки).
  2. Добавим ЛЕВОЕ СОЕДИНЕНИЕ в текст запроса.
  3. Свяжем таблицу документа или регистра с таблицей Справочник.Договоры.Ставки по полю Ссылка.

Пример модифицированного кода:


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

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

Решение 2. Передача таблицы значений как параметра запроса

Если логика заполнения сложная и данные из договора нужно предварительно обработать в коде перед попаданием в запрос, воспользуемся методом передачи Таблицы Значений (ТЗ) в качестве параметра запроса. Этот метод часто используется, когда данные нужно объединить из разных источников в оперативной памяти.

Рассмотрим реализацию этого метода. Сначала мы выгружаем данные из договора в ТЗ, а затем передаем их в запрос. Проанализируем пример кода:


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

Внимание: при использовании таблицы значений в запросе помните о типизации. Если вы создаете Таблицу Значений программно (через Новый ТаблицаЗначений), то у колонок обязательно должно быть задано ОписаниеТипов. Если ТЗ получена методом Выгрузить() из существующей табличной части, типы колонок будут определены автоматически.

Решение 3. Использование объектной техники (Для простых случаев)

Если нам не нужно соединять данные в сложном запросе, а требуется просто перенести строки «как есть» из справочника в документ, мы можем обойтись циклом. Посмотрим на этот вариант:


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

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

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

Для эффективной работы в 1С:Предприятии на управляемых формах при получении данных из табличных частей справочников рекомендуем придерживаться следующих правил:

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

← На главную