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

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

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

Постановка задачи и анализ исходных данных

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

  1. Сформировать запрос, который получит нужные данные.
  2. Передать в запрос параметр (должность).
  3. Очистить существующие строки в табличной части, чтобы избежать дублирования.
  4. Добавить новые строки на основе результата запроса.

Вариант 1: Заполнение через цикл и метод Добавить()

Это классический способ, который позволяет гибко управлять процессом добавления каждой строки. Рассмотрим исправленный код, который обсуждался на форуме. Основная ошибка автора заключалась в том, что он пытался выбрать данные из самого документа, который еще не заполнен, вместо того чтобы обратиться к источнику настроек (например, справочнику или другому документу-шаблону).

Разберем пример кода, который реализует заполнение через обход выборки запроса:


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

В этом примере метод ЗаполнитьЗначенияСвойств значительно упрощает код, так как он автоматически ищет поля в выборке запроса, имена которых совпадают с именами колонок табличной части, и копирует их значения.

Вариант 2: Оптимизированное заполнение через метод Загрузить()

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

Проанализируем этот подход:


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

Преимущество: Этот метод работает быстрее на больших объемах данных, так как выполняется одной операцией в памяти платформы без явного цикла на языке 1С.

Важные нюансы и рекомендации

При реализации подобных механизмов следует обратить внимание на несколько критически важных моментов, которые часто упускают начинающие разработчики:

1. Работа с контекстом (Объект и ДанныеФормы)

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

2. Обязательная очистка данных

Всегда используйте Объект.ИмяТабличнойЧасти.Очистить() перед началом заполнения. Если этого не сделать, каждое нажатие пользователем кнопки «Заполнить» будет дублировать строки в таблице, что приведет к ошибкам в учете.

3. Псевдонимы в запросе

При использовании ЗаполнитьЗначенияСвойств или Загрузить() крайне важно следить за именами полей. Если в ТЧ колонка называется ВидДеятельности, а в запросе вы выбрали поле как Вид, данные не перенесутся. Всегда используйте оператор КАК в тексте запроса для приведения имен к единообразию.

4. Проверка на пустой результат

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


Если ТаблицаРезультат.Количество() = 0 Тогда
    Сообщение = Новый СообщениеПользователю;
    Сообщение.Текст = "Для выбранной должности не заданы этапы адаптации!";
    Сообщение.Сообщить();
КонецЕсли;

5. Архитектурный подход

Как справедливо заметили участники обсуждения, хранение настроек внутри других документов не всегда оптимально. Если связь «Должность — Виды адаптации» является условно-постоянной информацией, лучше хранить её в Регистре сведений или как табличную часть справочника Должности. Это обеспечит более высокую скорость выборки и логичную структуру базы данных.

Таким образом, выбор между циклом Пока Выборка.Следующий() и методом Загрузить() зависит от сложности бизнес-логики. Для простого копирования данных Загрузить() идеален, а для сложных расчетов при заполнении лучше использовать обход выборки.

← На главную