Как исправить ошибку Поле объекта не обнаружено Колонки и правильно перебрать динамические колонки таблицы в 1С

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

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

Анализируем причину возникновения ошибки

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


Для Каждого ТекСтрока Из Форма.ТаблицаФормы Цикл
    // ОШИБКА: У строки нет свойства "Колонки"
    Для Каждого Колонка Из ТекСтрока.Колонки Цикл 
        // Какая-то логика
    КонецЦикла;
КонецЦикла;

Проанализируем ситуацию: объект ТекСтрока является типом ДанныеФормыЭлементКоллекции. В 1С этот объект представляет собой конкретную запись данных, и он "знает" только о значениях полей этой записи. Сведения о том, какие вообще колонки существуют в таблице (метаданные таблицы), хранятся в самом родителе — объекте ТаблицаФормы (или в реквизите, к которому она привязана). Таким образом, обращение к свойству Колонки через переменную строки — это принципиальная ошибка типизации.

Правильный способ перебора колонок в цикле по строкам

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

Шаг 1. Получение списка колонок. Поскольку на управляемой форме мы работаем с объектом ДанныеФормыКоллекция, у него нет прямого свойства Колонки, как у обычной ТаблицыЗначений. Один из самых простых (хотя и не всегда самых быстрых) способов — временно выгрузить структуру колонок.

Шаг 2. Обход строк. Используем полученный массив или коллекцию имен колонок внутри цикла по строкам таблицы.

Рассмотрим пример кода, который решает эту задачу корректно:


// Получаем коллекцию колонок из реквизита формы (таблицы)
// Если это реквизит формы типа ДанныеФормыКоллекция:
КолонкиТаблицы = Форма.ТаблицаФормы.Выгрузить().Колонки; 

Для Каждого ТекСтрока Из Форма.ТаблицаФормы Цикл
    
    // Перебираем коллекцию колонок, полученную ранее
    Для Каждого Колонка Из КолонкиТаблицы Цикл
        
        ИмяКолонки = Колонка.Имя;
        
        // Исключаем служебные колонки, если это необходимо
        Если ИмяКолонки = "Показатель" Тогда
            Продолжить;
        КонецЕсли;
        
        // Получаем значение ячейки по имени колонки
        ЗначениеЯчейки = ТекСтрока[ИмяКолонки];
        
        // Далее выполняем логику сохранения или обработки
        // Например, поиск в табличной части документа
        ПараметрыОтбора = Новый Структура("Показатель, ИмяКолонки", ТекСтрока.Показатель, ИмяКолонки);
        НайденныеСтроки = Объект.Показатели.НайтиСтроки(ПараметрыОтбора);
        
        Если НайденныеСтроки.Количество() > 0 Тогда
            НайденныеСтроки[0].Значение = ЗначениеЯчейки;
        КонецЕсли;
        
    КонецЦикла;
    
КонецЦикла;

Оптимизация производительности: работа с именами колонок

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

  1. Создаем массив МассивИменКолонок.
  2. Один раз заполняем его перед началом всех циклов.
  3. В основном цикле по строкам используем только этот массив.

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

Нюансы сохранения данных: Объект или ТекущийОбъект?

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

Если вы передаете Объект в общий модуль для обработки:

Если задача стоит — сохранить данные "тихо" на сервере, нам нужно использовать метод РеквизитФормыВЗначение("Объект"). Рассмотрим, как это выглядит в комплексе:


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

Как проверить наличие данных и избежать ошибок индексации

Посмотрим на пример из практики: использование метода НайтиСтроки(). Программисты часто сразу обращаются к результату через [0], например: ТекПоказателей[0].Значение = .... Это крайне опасная практика! Если метод НайтиСтроки() не найдет совпадений, он вернет пустой массив, и программа завершится аварийно с ошибкой "Индекс находится за пределами границы".

Всегда проверяйте количество найденных строк:


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

Подведем итоги

Работа с динамическими структурами в 1С требует внимательного отношения к типам объектов. Основные правила, которые мы выявили:

  1. Никогда не ищите свойство Колонки у строки таблицы. Обращайтесь к коллекции колонок через саму таблицу или предварительно выгруженные метаданные.
  2. Используйте квадратные скобки для доступа к данным ячейки по строковому имени колонки: Строка[ИмяКолонки].
  3. Кэшируйте имена колонок. Если вы планируете большой цикл, лучше один раз собрать имена колонок в массив и работать с ним.
  4. Различайте данные формы и объекты базы данных. Помните, что для окончательной фиксации изменений в базе данных чаще всего требуется работа с объектом, полученным через РеквизитФормыВЗначение.

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

← На главную