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

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

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

Способ 1. Использование универсальной функции со вспомогательной структурой

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

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


// Проверяет наличие реквизита или свойства у произвольного объекта без обращения к метаданным.
Функция ЕстьРеквизитИлиСвойствоОбъекта(Объект, ИмяРеквизита) Экспорт
    
    // Создаем уникальный маркер, которого точно нет в данных
    КлючУникальности   = Новый УникальныйИдентификатор;
    
    // Создаем структуру с искомым именем поля
    СтруктураРеквизита = Новый Структура(ИмяРеквизита, КлючУникальности);
    
    // Пытаемся скопировать данные из объекта в структуру
    // Если поле в объекте есть, значение КлючУникальности будет перезаписано
    ЗаполнитьЗначенияСвойств(СтруктураРеквизита, Объект);
    
    // Если значение в структуре больше не равно нашему маркеру, реквизит найден
    Возврат СтруктураРеквизита[ИмяРеквизита] <> КлючУникальности;
    
КонецФункции

Преимущества: метод работает на клиенте и на сервере, не требует наличия ссылки на документ и не нагружает систему обращениями к метаданным. Важный нюанс: этот способ вернет Истина, даже если значение реквизита равно Неопределено или Null.

Способ 2. Проверка через метаданные объекта

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

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


// Предположим, ОбъектСсылка — это ссылка на документ, а "Товары" — имя ТЧ
Если ОбъектСсылка.Метаданные().ТабличныеЧасти.Товары.Реквизиты.Найти("Мест") <> Неопределено Тогда
    // Реквизит существует, можно выполнять логику
    Сообщить("Колонка 'Мест' найдена в метаданных!");
КонецЕсли;

Если же мы работаем внутри модуля объекта и хотим проверить колонку конкретной табличной части, к которой принадлежит строка, можно пойти по пути определения владельца. Для объекта типа ТаблицаЗначений это выглядит так:


// СтрокаТЧ — это строка таблицы значений
Если СтрокаТЧ.Владелец().Колонки.Найти("Мест") <> Неопределено Тогда
    // Работаем с колонкой
КонецЕсли;

Способ 3. Использование Библиотеки стандартных подсистем (БСП)

Выясним, есть ли готовые решения в типовых конфигурациях (таких как БП 3.0, УТ 11, ERP). В составе БСП есть общий модуль ОбщегоНазначения (или ОбщегоНазначенияКлиентСервер), который содержит оптимизированные функции для подобных проверок.

Проанализируем вызов такой функции:


// Использование типовой функции БСП
Если ОбщегоНазначения.ЕстьРеквизитОбъекта(СтрокаТЧ, "Мест") Тогда
    // Реквизит присутствует
КонецЕсли;

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

Способ 4. Перехват исключения (Try-Except)

Рассмотрим еще один метод, который часто называют «ленивым». Он заключается в попытке прямого обращения к полю. Если поля нет, платформа сгенерирует ошибку, которую мы перехватим.


ЕстьРеквизит = Ложь;
Попытка
    ТестовоеЗначение = СтрокаТЧ.Мест;
    ЕстьРеквизит = Истина;
Исключение
    // Сюда попадем, если реквизита "Мест" не существует в данном объекте
    ЕстьРеквизит = Ложь;
КонецПопытки;

Важно понимать: использование конструкции Попытка...Исключение крайне не рекомендуется внутри высоконагруженных циклов. Генерация исключения в 1С — ресурсоемкая операция. Однако для разовой проверки в интерфейсе этот метод вполне допустим.

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

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

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

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

Для выбора оптимального решения воспользуемся следующими правилами:

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