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

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

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

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

Способ 1. Обход табличной части с помощью цикла

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

Многие начинающие пытаются применить к табличной части метод Выбрать(), характерный для результатов запроса или выборок из базы данных. Однако табличная часть на форме — это объект типа ДанныеФормыКоллекция, и для неё такой метод не определен. Правильным подходом будет использование цикла Для каждого.

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


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

Этот способ универсален и понятен. Мы поочередно заходим в каждую строку коллекции Объект.ПереченьДокументов и проверяем значение флажка.

Способ 2. Оптимизированный поиск строк через НайтиСтроки

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

Разберем, как это работает на практике:


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

Этот метод работает быстрее, так как платформа оптимизирует поиск внутри коллекции ДанныеФормыКоллекция.

Критическая ошибка: Использование переменной Объект

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


// ОШИБОЧНЫЙ КОД
Для Каждого ТекущаяСтрока Из Объект.ПереченьДокументов Цикл
    Если ТекущаяСтрока.Использование Тогда
        Объект = ТекущаяСтрока.Документ.ПолучитьОбъект(); // КАТАСТРОФА!
        Объект.Записать();
    КонецЕсли;
КонецЦикла;

Почему это нельзя делать? В модуле управляемой формы слово Объект является зарезервированным. Оно указывает на саму вашу внешнюю обработку и все её данные. Как только вы пишете Объект = ..., вы затираете в памяти сервера данные всей формы. После этого цикл сломается, а данные в табличной части могут «испариться» или привести к ошибке «Объект не обнаружен».

Как правильно: всегда используйте уникальное имя переменной для документа, например ДокументОбъект или ТекущийДок.


// ПРАВИЛЬНЫЙ КОД
Для Каждого ТекущаяСтрока Из Объект.ПереченьДокументов Цикл
    Если ТекущаяСтрока.Использование Тогда
        // Создаем отдельную переменную, не трогая системный "Объект"
        ДокументОбъект = ТекущаяСтрока.Документ.ПолучитьОбъект();
        Если ДокументОбъект <> Неопределено Тогда
            // Проводим необходимые расчеты
            ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Работа с типами данных: Ссылка vs Объект

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

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

Также важно помнить, что работа с объектами (ПолучитьОбъект, Записать) возможна только на сервере. На клиенте вы можете работать только со ссылками и простыми типами данных (строки, числа).

Запросы к данным табличной части

Проанализируем ситуацию, когда данных очень много и простого цикла недостаточно. Начинающие часто спрашивают: «Как написать запрос к моей табличной части?». Напрямую — никак, так как таблицы на форме не хранятся в базе данных SQL, они существуют только в оперативной памяти.

Чтобы использовать мощь языка запросов для данных из вашей обработки, нужно выполнить следующие шаги:

  1. Выгрузить табличную часть в обычную ТаблицаЗначений.
  2. Передать эту таблицу в запрос как параметр.
  3. В тексте запроса использовать создание временной таблицы.

Пример реализации:


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

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

Подводя итог, при работе с внешними обработками придерживайтесь правила: отбирайте данные на сервере, храните их в типизированных колонках табличной части, обходите через цикл Для каждого и никогда не перезаписывайте переменную Объект. Это обеспечит стабильную работу вашего кода и отсутствие трудноуловимых ошибок.

← На главную