Разработка в системе 1С:Предприятие 8.3 часто ставит перед программистом задачи по проверке типов данных. Одной из неочевидных проблем является сравнение типа конкретной табличной части документа с эталонным значением. Казалось бы, стандартная конструкция ТипЗнч() должна работать безупречно, однако в определенных контекстах, таких как модули HTTP-сервисов или фоновые задания, разработчики сталкиваются с тем, что идентичные на первый взгляд типы при сравнении дают результат Ложь.
В этой статье мы подробно разберем, почему стандартное сравнение может не работать, и рассмотрим наиболее надежные способы идентификации табличных частей документов через метаданные и другие механизмы платформы.
Рассмотрим классическую ситуацию. У нас есть документ ПриобретениеТоваровУслуг, и мы хотим убедиться, что переданная в переменную коллекция является именно табличной частью Товары этого документа. На первый взгляд, решение выглядит просто:
Если ТипЗнч(ПеременнаяСКоллекцией) = Тип("ДокументТабличнаяЧасть.ПриобретениеТоваровУслуг.Товары") Тогда
// Выполняем действия
КонецЕсли;
Однако на практике, особенно при работе в модулях HTTP-сервисов или при выполнении кода на сервере в специфических сессиях, это условие может не выполняться. Причина кроется во внутренних механизмах платформы 1С. Тип ДокументТабличнаяЧасть является составным и динамическим. В некоторых случаях платформа может по-разному инициализировать описатели типов в разных программных контекстах. Несмотря на то, что отладчик показывает строковое представление типа как "Document Tabular section: Товары", внутренние идентификаторы типов могут различаться.
Проанализируем наиболее устойчивый к контексту исполнения метод. Вместо прямого сравнения типов данных, мы можем обратиться к глобальному объекту Метаданные. Метод НайтиПоТипу() позволяет получить объект описания метаданных для любого значения, имеющего тип, зарегистрированный в конфигурации.
Разберем этот способ по шагам:
ТипЗнч().Метаданные.НайтиПоТипу(), чтобы найти соответствующий узел в дереве метаданных.Пример реализации кода:
// Предположим, Значение111 — это наша табличная часть
ТипОбъекта = ТипЗнч(Значение111);
ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипОбъекта);
Если ОбъектМетаданных = Метаданные.Документы.ПриобретениеТоваровУслуг.ТабличныеЧасти.Товары Тогда
Сообщить("Это именно табличная часть 'Товары' нужного документа!");
КонецЕсли;
Этот метод считается эталонным, так как объекты метаданных в рамках одного сеанса работы всегда идентичны сами себе. Он работает корректно даже там, где прямое сравнение типов через Тип() дает сбой.
Если нам нужно проверить не только саму табличную часть, но и убедиться, что она принадлежит конкретному типу документа, мы можем пойти «от обратного». Если в нашей переменной находится коллекция строк табличной части (объект типа ДокументТабличнаяЧасть), мы можем проверить тип самого документа-владельца.
Рассмотрим ситуацию, когда у нас есть ссылка на документ, и нам нужно проверить его ТЧ:
Если ТипЗнч(ДокументСсылка) = Тип("ДокументСсылка.ПриобретениеТоваровУслуг") Тогда
// Мы уже знаем тип документа. Теперь достаточно проверить имя ТЧ через метаданные,
// если это универсальный алгоритм.
КоллекцияТЧ = ДокументСсылка.Товары;
// Работаем с коллекцией...
КонецЕсли;
Если же мы получили коллекцию «вслепую» и хотим понять, чья она, можно попытаться получить доступ к метаданным через свойство Метаданные() (если объект это поддерживает) или использовать поиск по типу, описанный выше.
Для продвинутых задач, когда требуется максимальная абстракция (например, при передаче данных между разными узлами или в веб-сервисах), можно использовать механизм XMLТипЗнч. Этот метод возвращает универсальный идентификатор типа, который не зависит от локального представления платформы.
Выясним, как это работает:
НужныйТипXML = XMLТип(Тип("ДокументТабличнаяЧасть.ПриобретениеТоваровУслуг.Товары"));
ТекущийТипXML = XMLТипЗнч(Значение111);
Если ТекущийТипXML.ИмяТипа = НужныйТипXML.ИмяТипа
И ТекущийТипXML.URIПространстваИмен = НужныйТипXML.URIПространстваИмен Тогда
// Типы совпадают на уровне XML-описания
КонецЕсли;
Этот способ позволяет избежать проблем с «разными» типами в разных модулях, так как XML-имена типов жестко привязаны к структуре метаданных конфигурации.
Проанализируем причину, по которой автор вопроса столкнулся с проблемой именно в HTTP-сервисе. При вызове HTTP-сервиса платформа инициализирует минимально необходимый контекст. Иногда внутренние кэши типов для объектов метаданных (особенно для вложенных сущностей, таких как табличные части) могут инициализироваться иначе, чем в толстом или тонком клиенте. Использование прямой ссылки на объект метаданных через Метаданные.Документы... является наиболее стабильным способом, так как это прямое обращение к конфигурации, которое принудительно возвращает правильный дескриптор объекта.
При разработке сложных систем на базе 1С:Предприятие 8.3 рекомендуется придерживаться следующих правил при сравнении типов:
ТипЗнч(Ссылка) = Тип("...").Метаданные.НайтиПоТипу().Использование правильных методов сравнения типов сделает ваш код более надежным и устойчивым к изменениям платформы и контекста исполнения.