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

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

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

Обращение к табличной части на управляемой форме

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

  1. Элементы формы (Элементы) управляют визуальным отображением: видимостью, доступностью, цветом и положением колонок. Через них нельзя напрямую обойти строки данных стандартным циклом Для каждого.
  2. Данные формы (Объект) содержат саму структуру данных прикладного объекта. Если табличная часть принадлежит объекту обработки или документа, обращение к ней выполняется через реквизит формы Объект: Объект.Товары.

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


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

Почему очищается поле при программной замене значения

Проанализируем типичную ошибку: при создании нового элемента справочника в коде разработчик пытается присвоить созданный объект непосредственно в колонку табличной части. В результате колонка на форме становится пустой.

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

Для корректного заполнения необходимо обращаться к свойству Ссылка созданного объекта после его записи в базу данных:


&НаСервере
Процедура ТоварДоговор()
    Для Каждого ТекСтрока Из Объект.Товары Цикл
        Товар = ТекСтрока.Номенклатура.НаименованиеПолное;
        Договор = ТекСтрока.НомерДоговора;
        ТоварДоговор = Товар + " по договору " + Договор;
        
        НоваяНоменклатура = Справочники.Номенклатура.СоздатьЭлемент();
        НоваяНоменклатура.ВидНоменклатуры = Справочники.ВидыНоменклатуры.НайтиПоНаименованию("Основная номенклатура");
        НоваяНоменклатура.Наименование = ТоварДоговор;
        НоваяНоменклатура.ЕдиницаИзмерения = Справочники.БазовыеЕдиницыИзмерения.НайтиПоКоду("796");
        НоваяНоменклатура.Родитель = Справочники.Номенклатура.НайтиПоНаименованию("temp");
        НоваяНоменклатура.Записать();
        
        // Правильное присвоение: передаем Ссылку, а не Объект
        ТекСтрока.Номенклатура = НоваяНоменклатура.Ссылка;
    КонецЦикла;
КонецПроцедуры

Оптимизация работы с базой данных при создании элементов в цикле

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

  1. Вынос поиска настроек и предопределенных данных из цикла. Вызовы методов НайтиПоНаименованию() и НайтиПоКоду() на каждой итерации цикла выполняют отдельные запросы к СУБД. Значения вида номенклатуры, единицы измерения и группы-родителя следует получить один раз перед входом в цикл.
  2. Использование явной транзакции. Запись каждого элемента справочника без явной транзакции инициирует отдельную транзакцию в базе данных. Оборачивание всего цикла в блок НачатьТранзакцию() и ЗафиксироватьТранзакцию() значительно ускоряет массовую запись объектов.
  3. Проверка на дублирование. Если в табличной части присутствуют повторяющиеся комбинации номенклатуры и договора, создание элементов без проверки приведет к дублям в справочнике. Рекомендуется предварительно проверять наличие уже созданного элемента.

Посмотрим на оптимизированный пример процедуры:


&НаСервере
Процедура ТоварДоговорОптимизированно()
    // Получаем постоянные ссылки один раз до входа в цикл
    СсылкаВидНоменклатуры = Справочники.ВидыНоменклатуры.НайтиПоНаименованию("Основная номенклатура");
    СсылкаЕдиница = Справочники.БазовыеЕдиницыИзмерения.НайтиПоКоду("796");
    СсылкаРодитель = Справочники.Номенклатура.НайтиПоНаименованию("temp");
    
    НачатьТранзакцию();
    Попытка
        Для Каждого ТекСтрока Из Объект.Товары Цикл
            Товар = ТекСтрока.Номенклатура.НаименованиеПолное;
            Договор = ТекСтрока.НомерДоговора;
            ПолноеНаименование = Товар + " по договору " + Договор;
            
            // Создаем и заполняем элемент
            НовыйОбъект = Справочники.Номенклатура.СоздатьЭлемент();
            НовыйОбъект.ВидНоменклатуры = СсылкаВидНоменклатуры;
            НовыйОбъект.Наименование = ПолноеНаименование;
            НовыйОбъект.ЕдиницаИзмерения = СсылкаЕдиница;
            НовыйОбъект.Родитель = СсылкаРодитель;
            НовыйОбъект.Записать();
            
            ТекСтрока.Номенклатура = НовыйОбъект.Ссылка;
        КонецЦикла;
        
        ЗафиксироватьТранзакцию();
    Исключение
        ОтменитьТранзакцию();
        ВызватьИсключение;
    КонецПопытки;
КонецПроцедуры

Особенности работы с зависимыми реквизитами на форме

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

← На главную