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

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

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

Основы работы с объектом документа

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

  1. Передаем ссылку на документ с клиента на сервер.
  2. На сервере получаем объект документа с помощью метода ПолучитьОбъект().
  3. Производим обход строк табличной части.
  4. Меняем значения нужных реквизитов.
  5. Записываем объект в базу данных.

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


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

Оптимизация с использованием метода ЗаполнитьЗначения

Если перед нами стоит задача установить одинаковое значение во все строки табличной части, использование цикла Для Каждого может быть не самым производительным решением, особенно если строк в документе очень много (тысячи). Платформа 1С предоставляет встроенный оптимизированный метод ЗаполнитьЗначения() для коллекций строк.

Посмотрим, как упростится наш код:


&НаСервере
Процедура ОптимизированноеИзменение(СсылкаНаДокумент)
    ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
    
    // Первый параметр - значение, второй - имя реквизита (колонки ТЧ)
    ДокОбъект.Наряды.ЗаполнитьЗначения(Перечисления.СтатусНаряды.Отправлен, "Статус");
    
    ДокОбъект.Записать();
КонецПроцедуры

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

Решение проблемы Итератор для значения не определен

Разберем ситуацию, с которой часто сталкиваются начинающие разработчики при использовании сложных запросов. Если вы пытаетесь выбрать данные документа и его табличной части через запрос с использованием вложенной таблицы, вы можете столкнуться с ошибкой итератора. Выясним причину: при выборке вложенной таблицы результатом является не массив строк, а объект типа РезультатЗапроса, который нужно обходить дополнительной выборкой.

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


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

    Пока ВыборкаДокументов.Следующий() Цикл
        ДокОбъект = ВыборкаДокументов.Ссылка.ПолучитьОбъект();
        
        // КРИТИЧЕСКИ ВАЖНО: Для вложенной таблицы нужно снова вызвать метод Выбрать()
        ВыборкаСтрок = ВыборкаДокументов.ТаблицаНарядов.Выбрать();
        
        Пока ВыборкаСтрок.Следующий() Цикл
            // Обращаемся к строке ТЧ по индексу (НомерСтроки начинается с 1)
            Индекс = ВыборкаСтрок.НомерСтроки - 1;
            ДокОбъект.Наряды[Индекс].Статус = Перечисления.СтатусНаряды.Отправлен;
        КонецЦикла;
        
        ДокОбъект.Записать();
    КонецЦикла;
КонецФункции

Обновление данных на форме после изменения

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

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


&НаКлиенте
Процедура КомандаИзменитьСтатус(Команда)
    ТекДанные = Элементы.СписокДокументов.ТекущиеДанные;
    Если ТекДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    
    // Вызываем серверный метод изменения
    СерверноеИзменение(ТекДанные.Ссылка);
    
    // Обновляем динамический список, чтобы увидеть результат
    Элементы.СписокДокументов.Обновить();
    
    Сообщить("Данные успешно обновлены!");
КонецПроцедуры

Важные рекомендации по работе с блокировками и правами

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

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

← На главную