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

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

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

Почему нельзя изменить строку прямо из выборки запроса

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

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

Способ 1. Получение объекта документа и метод НайтиСтроки()

Рассмотрим наиболее популярный способ поиска и редактирования строки. Сначала получаем ссылку на документ, затем вызываем метод ПолучитьОбъект() и производим поиск по ключевым колонкам табличной части с помощью метода НайтиСтроки().

Разберем по шагам пример кода:


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

Запрос.УстановитьПараметр("Номер", "О-ИП0016647");
Выборка = Запрос.Выполнить().Выбрать();

// 2. Обходим результаты и модифицируем объект
Пока Выборка.Следующий() Цикл
    ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
    
    // Подготавливаем отбор по ключевому полю (например, Номенклатура)
    Отбор = Новый Структура("Номенклатура", Справочники.Номенклатура.НайтиПоКоду("С-000000788"));
    НайденныеСтроки = ДокОбъект.Товары.НайтиСтроки(Отбор);
    
    Если НайденныеСтроки.Количество() > 0 Тогда
        // Редактируем первую найденную строку
        СтрокаТЧ = НайденныеСтроки[0];
        СтрокаТЧ.Количество = 123;
    КонецЕсли;
    
    // Записываем измененный объект
    ДокОбъект.Записать();
КонецЦикла;

Способ 2. Использование поля НомерСтроки из запроса

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

Обратите внимание: нумерация строк в табличных частях 1С начинается с 1, а индексация элементов в коде — с 0. Поэтому индекс строки рассчитывается как НомерСтроки - 1.

Посмотрим на следующий пример:


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

Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
Выборка = Запрос.Выполнить().Выбрать();

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

Способ 3. Получение текущей строки в контексте формы

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

В этом случае работа происходит через элементы формы и реквизит формы:

  1. В управляемых формах: текущую строку элемента формы можно получить через Элементы.ОтработанноеВремя.ТекущиеДанные.
  2. В обычных формах: используем ЭлементыФормы.ОтработанноеВремя.ТекущиеДанные.

Пример изменения строки на форме:


ТекущаяСтрока = Элементы.ОтработанноеВремя.ТекущиеДанные;
Если ТекущаяСтрока <> Неопределено Тогда
    ТекущаяСтрока.Часов = 8;
КонецЕсли;

Оптимизация работы и предотвращение ошибок

Разберем важные рекомендации по написанию чистого и производительного кода при работе с табличными частями:

  1. Не вызывайте НайтиПоНаименованию() или НайтиПоКоду() внутри циклов: такие вызовы обращаются к базе данных на каждом шаге цикла. Передавайте условия и готовые ссылки или списки значений прямо в параметры запроса.
  2. Не создавайте запрос, если доступен сам документ: если у вас уже есть объект документа, обходить его строки можно простым циклом Для Каждого СтрокаТЧ Из ДокОбъект.ОтработанноеВремя Цикл ... КонецЦикла; без выполнения лишних запросов.
  3. Использование флага Загрузка: если при программном изменении строк документа не требуется выполнять тяжелые проверки в модуле объекта (например, при отработке обменов или заполнении), используйте свойство ДокОбъект.ОбменДанными.Загрузка = Истина; перед вызовом Записать().
← На главную