Как правильно выполнять отбор по полю Владелец (Owner) через 1С OData

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

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

Анализ проблемы и исследование метаданных

Рассмотрим стандартную ситуацию: нам необходимо получить все характеристики для конкретной номенклатуры, зная ее GUID. Мы анализируем метаданные ($metadata) и видим следующую структуру для сущности Catalog_ХарактеристикиНоменклатуры:


<Property Name="Owner" Type="Edm.String" Nullable="true"/>
<Property Name="Description" Type="Edm.String" Nullable="true"/>
<Property Name="Owner_Type" Type="Edm.String" Nullable="true"/>

На первый взгляд, поле Owner является обычной строкой. Мы логично предполагаем, что обычный фильтр по строковому представлению GUID должен сработать. Однако запрос вида $filter=Owner eq 'ae8d0dac-5a7c-11ed-88ce-d8bbc189bb8e' возвращает пустой массив value: []. При этом аналогичный фильтр по полю Description отрабатывает корректно. Проанализируем ситуацию: почему два поля с одинаковым типом Edm.String ведут себя по-разному?

Почему стандартное сравнение со строкой не работает

Выясним причину такого поведения. В платформе 1С поле Владелец почти всегда является составным типом данных. Даже если в конфигураторе в качестве владельца указан только один справочник, системно 1С закладывает возможность расширения. В протоколе OData 3.0, который используется в 1С, нет нативного типа для передачи "произвольной ссылки". Поэтому платформа маскирует такие поля под Edm.String.

Важный технический нюанс: в базе данных 1С ссылки хранятся в бинарном 16-байтовом формате. Когда мы отправляем запрос с фильтром eq 'строка', система пытается выполнить прямое текстовое сравнение в SQL-запросе. Но в колонке владельца хранятся не строки, а двоичные данные (ссылки). Поскольку типы не совпадают на уровне движка базы данных, 1С не может сопоставить ваш текстовый GUID с бинарным идентификатором, и результат оказывается пустым.

Если же мы попробуем использовать литерал guid'...' напрямую (например, $filter=Owner eq guid'...'), то получим ошибку совместимости типов:

"Неверные параметры в операции сравнения. Нельзя сравнивать поля неограниченной длины и поля несовместимых типов."

Это происходит потому, что метаданные жестко задекларировали Owner как Edm.String, и OData-протокол запрещает сравнивать строку с типом Guid напрямую.

Основное решение: использование функции cast()

Единственным правильным способом выполнения отбора по ссылочным полям, которые в метаданных помечены как строки, является использование функции cast(). В контексте 1С OData эта функция работает не просто как приведение типов, а как конструктор объекта "Ссылка".

Проанализируем синтаксис правильного запроса:


https://server/db/odata/standard.odata/Catalog_ХарактеристикиНоменклатуры?$filter=Owner eq cast(guid'ae8d0dac-5a7c-11ed-88ce-d8bbc189bb8e', 'Catalog_Номенклатура')

Разберем по шагам, что происходит в этом запросе:

  1. Мы берем строковый идентификатор и оборачиваем его в литерал guid'...', чтобы система понимала, что это уникальный идентификатор, а не просто набор символов.
  2. Используем функцию cast(), где вторым параметром указываем имя сущности в формате 1С OData (например, 'Catalog_Номенклатура').
  3. Платформа 1С, получив такой запрос, понимает: "Нужно взять этот GUID, найти объект в таблице Номенклатуры и использовать полученную внутреннюю ссылку для фильтрации таблицы Характеристик".

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

Альтернативный подход: фильтрация через навигационные свойства

Если использование функции cast() кажется вам громоздким, рассмотрим другой способ, который часто применяется в разработке. Если в вашей версии платформы и конфигурации для поля Owner создано навигационное свойство (Navigation Property), вы можете обратиться к его внутреннему ключу Ref_Key, который всегда имеет тип Edm.Guid.

Посмотрим на пример такого запроса:


$filter=Owner/Ref_Key eq guid'ae8d0dac-5a7c-11ed-88ce-d8bbc189bb8e'

Преимущества этого метода:

Метод "от обратного" через $expand

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

Рассмотрим пример запроса:


https://server/db/odata/standard.odata/Catalog_Номенклатура(guid'ae8d0dac-5a7c-11ed-88ce-d8bbc189bb8e')?$expand=Характеристики

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

Резюме и рекомендации

Подведем итоги нашего анализа. Столкнувшись с пустым результатом при фильтрации в 1С OData, выполните следующие действия:

  1. Проверьте тип поля в $metadata. Если это Edm.String, но поле ссылается на объект (как Owner), обычное текстовое сравнение eq '...' не сработает.
  2. Используйте cast(guid'UUID', 'Target_Type') для корректного преобразования.
  3. Обращайте внимание на суффикс _Type в метаданных. Наличие поля Owner_Type — явный признак того, что основное поле требует особого обращения через cast.
  4. Следите за регистром и правильностью написания имен сущностей (например, Catalog_ вместо Справочник.).

Использование функции cast() — это не просто "хак", а штатный механизм платформы для работы с полиморфными (составными) типами данных в условиях ограничений протокола OData 3.0. Понимание этого механизма позволит вам строить надежные интеграции с системой 1С.

← На главную