В процессе разработки на платформе 1С:Предприятие часто возникают ситуации, когда необходимо написать универсальный алгоритм для обработки строк табличных частей различных документов или справочников. Основная сложность заключается в том, что состав колонок в разных объектах может отличаться. Чтобы программа не аварийно завершалась при попытке обращения к несуществующему полю Мест (или любому другому), нам нужно предварительно проверить его наличие. Рассмотрим подробнее несколько надежных способов решения этой задачи.
Проанализируем ситуацию, когда у нас в руках есть только строка (например, типа ДанныеФормыЭлементКоллекции или СтрокаТаблицыЗначений), и мы не хотим или не можем обращаться к метаданным всего объекта. В этом случае отлично работает «хак» с использованием структуры и метода ЗаполнитьЗначенияСвойств. Этот метод считается одним из самых быстрых и универсальных.
Разберем логику этого метода: мы создаем структуру, где ключом является имя искомого реквизита, а значением — уникальный идентификатор. Затем мы пытаемся заполнить эту структуру из нашей строки. Если значение в структуре изменилось — значит, реквизит в строке существует.
// Проверяет наличие реквизита или свойства у произвольного объекта без обращения к метаданным.
Функция ЕстьРеквизитИлиСвойствоОбъекта(Объект, ИмяРеквизита) Экспорт
// Создаем уникальный маркер, которого точно нет в данных
КлючУникальности = Новый УникальныйИдентификатор;
// Создаем структуру с искомым именем поля
СтруктураРеквизита = Новый Структура(ИмяРеквизита, КлючУникальности);
// Пытаемся скопировать данные из объекта в структуру
// Если поле в объекте есть, значение КлючУникальности будет перезаписано
ЗаполнитьЗначенияСвойств(СтруктураРеквизита, Объект);
// Если значение в структуре больше не равно нашему маркеру, реквизит найден
Возврат СтруктураРеквизита[ИмяРеквизита] <> КлючУникальности;
КонецФункции
Преимущества: метод работает на клиенте и на сервере, не требует наличия ссылки на документ и не нагружает систему обращениями к метаданным. Важный нюанс: этот способ вернет Истина, даже если значение реквизита равно Неопределено или Null.
Если у нас есть доступ к самому объекту (документу, справочнику) или его ссылке, мы можем использовать встроенные механизмы метаданных. Это наиболее «правильный» с точки зрения архитектуры платформы путь.
Посмотрим на пример кода, если нам известна табличная часть:
// Предположим, ОбъектСсылка — это ссылка на документ, а "Товары" — имя ТЧ
Если ОбъектСсылка.Метаданные().ТабличныеЧасти.Товары.Реквизиты.Найти("Мест") <> Неопределено Тогда
// Реквизит существует, можно выполнять логику
Сообщить("Колонка 'Мест' найдена в метаданных!");
КонецЕсли;
Если же мы работаем внутри модуля объекта и хотим проверить колонку конкретной табличной части, к которой принадлежит строка, можно пойти по пути определения владельца. Для объекта типа ТаблицаЗначений это выглядит так:
// СтрокаТЧ — это строка таблицы значений
Если СтрокаТЧ.Владелец().Колонки.Найти("Мест") <> Неопределено Тогда
// Работаем с колонкой
КонецЕсли;
Выясним, есть ли готовые решения в типовых конфигурациях (таких как БП 3.0, УТ 11, ERP). В составе БСП есть общий модуль ОбщегоНазначения (или ОбщегоНазначенияКлиентСервер), который содержит оптимизированные функции для подобных проверок.
Проанализируем вызов такой функции:
// Использование типовой функции БСП
Если ОбщегоНазначения.ЕстьРеквизитОбъекта(СтрокаТЧ, "Мест") Тогда
// Реквизит присутствует
КонецЕсли;
Почему это удобно: типовые функции уже учитывают особенности различных типов объектов (ссылки, выборки, строки) и зачастую кэшируют результаты проверок метаданных, что положительно сказывается на производительности.
Рассмотрим еще один метод, который часто называют «ленивым». Он заключается в попытке прямого обращения к полю. Если поля нет, платформа сгенерирует ошибку, которую мы перехватим.
ЕстьРеквизит = Ложь;
Попытка
ТестовоеЗначение = СтрокаТЧ.Мест;
ЕстьРеквизит = Истина;
Исключение
// Сюда попадем, если реквизита "Мест" не существует в данном объекте
ЕстьРеквизит = Ложь;
КонецПопытки;
Важно понимать: использование конструкции Попытка...Исключение крайне не рекомендуется внутри высоконагруженных циклов. Генерация исключения в 1С — ресурсоемкая операция. Однако для разовой проверки в интерфейсе этот метод вполне допустим.
При работе на управляемой форме строка табличной части обычно имеет тип ДанныеФормыЭлементКоллекции. Проанализируем важный момент: иногда колонка может присутствовать на форме (как элемент управления), но отсутствовать в данных самого объекта (в метаданных).
Если вам нужно проверить наличие колонки именно в данных формы, используйте метод ЗаполнитьЗначенияСвойств, описанный в первом способе. Если же нужно понять, сохранится ли это значение в базу данных, всегда обращайтесь к Метаданные() основного реквизита формы.
Для выбора оптимального решения воспользуемся следующими правилами: