Как получить данные из регистра сведений вместе с объектами через OData в 1С?

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

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

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

Анализ проблемы: почему данных нет в объекте?

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

Пытаясь получить данные через /odata/standard.odata/Document_СчетНаОплатуПокупателю, мы видим только стандартные поля: дату, номер, контрагента и т.д. Поля «Статус» там просто не существует. Рассмотрим, как решить эту задачу правильно.

Решение №1: Запрос «от обратного» через навигационные свойства

Одной из самых частых ошибок является попытка «дотянуться» от документа к регистру. В архитектуре OData 1С навигационные свойства (связи) обычно строятся от записи регистра к объекту, на который она ссылается. Вместо того чтобы запрашивать список счетов, мы запросим записи регистра и попросим 1С «подтянуть» данные связанных документов.

Рассмотрим структуру запроса, который позволит за один раз получить и статус, и данные счета. Выясним, какое измерение в регистре InformationRegister_СтатусыДокументов отвечает за связь с документом (обычно это поле Объект или Документ).

Пример запроса:


GET /odata/standard.odata/InformationRegister_СтатусыДокументов?$expand=Объект&$filter=Объект_Type eq 'StandardODATA.Document_СчетНаОплатуПокупателю'

В этом примере мы используем параметр $expand. Он заставляет сервер включить в ответ не только идентификатор (GUID) счета, но и все его реквизиты. Параметр $filter с конструкцией _Type позволяет нам ограничить выборку только счетами на оплату, если регистр хранит статусы для разных типов документов.

Решение №2: Использование виртуальных таблиц SliceLast (СрезПоследних)

Если регистр сведений является периодическим (т.е. хранит историю изменений статусов во времени), обычный запрос к InformationRegister_СтатусыДокументов вернет вам все записи за все время. Это избыточно. Для получения только актуального статуса в 1С предусмотрена виртуальная таблица СрезПоследних.

В интерфейсе OData она доступна через суффикс _SliceLast. Проанализируем, как это применить:


GET /odata/standard.odata/InformationRegister_СтатусыДокументов_SliceLast(Condition='...', Period=datetime'2023-10-27T00:00:00')?$expand=Объект

Использование SliceLast гарантирует, что для каждого счета вы получите только одну, самую свежую запись. Это кардинально снижает объем передаваемого трафика и упрощает обработку данных на стороне внешней системы.

Решение №3: Пакетные запросы ($batch) для оптимизации производительности

Бывают ситуации, когда вам уже известен список GUID конкретных счетов (например, 100 штук), и вам нужно узнать их статусы. Вместо 100 отдельных GET-запросов, мы воспользуемся механизмом пакетирования. Пакетный запрос позволяет объединить множество команд в одном HTTP-запросе.

Рассмотрим пример формирования тела POST запроса к эндпоинту $batch:


--batch_id_1
Content-Type: application/http
Content-Transfer-Encoding: binary

GET InformationRegister_СтатусыДокументов_SliceLast?$filter=Объект_Key eq guid'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' HTTP/1.1

--batch_id_1
Content-Type: application/http
Content-Transfer-Encoding: binary

GET InformationRegister_СтатусыДокументов_SliceLast?$filter=Объект_Key eq guid'yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy' HTTP/1.1
--batch_id_1--

Сервер 1С обработает все эти запросы внутри одной транзакции (или последовательно) и вернет один массив ответов. Это решает проблему сетевых задержек (Latency), которая является основной причиной медленной работы OData.

Решение №4: Фильтрация по времени изменения данных

Одной из проблем, озвученных в теме, было отсутствие поля «Дата изменения» в регистре. Однако, если регистр периодический, у него всегда есть системное поле Period. Мы можем использовать его для получения только тех статусов, которые изменились за последнюю неделю:


GET /odata/standard.odata/InformationRegister_СтатусыДокументов?$filter=Period gt datetime'2023-10-20T00:00:00' and Объект_Type eq 'StandardODATA.Document_СчетНаОплатуПокупателю'

Если же регистр непериодический, и в него не добавили специальный ресурс «ДатаИзменения», то отфильтровать новые записи стандартными средствами OData будет невозможно. В этом случае придется либо модифицировать конфигурацию (добавлять реквизит с датой), либо использовать поле DataVersion.

DataVersion — это системное поле типа RowVersion, которое меняется при любом обновлении записи. Хотя оно не является датой в привычном понимании, внешняя система может запоминать максимальное значение DataVersion из предыдущей загрузки и запрашивать записи, где DataVersion больше известного значения.

Решение №5: Пагинация через $top и $skip

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

  1. Используйте $top для ограничения количества записей в одном ответе (например, по 1000).
  2. Используйте $skip для смещения при следующем запросе.
  3. Обязательно используйте $orderby, чтобы порядок записей был детерминированным, иначе пагинация может пропустить данные.

Пример запроса первой тысячи записей:


GET /odata/standard.odata/InformationRegister_СтатусыДокументов?$orderby=Period&$top=1000&$skip=0&$expand=Объект

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

Мы выяснили, что отсутствие нужного поля в объекте 1С — это не тупик для OData. Основная стратегия заключается в том, чтобы найти регистр, в котором хранятся эти данные, и строить запрос от него к документу через $expand. Для тестирования и быстрого построения таких URL-адресов можно использовать генератор запросов OData.

Ключевые рекомендации:

Следуя этим правилам, мы сможем построить надежный и быстрый обмен данными с 1С, используя исключительно стандартные средства платформы.

← На главную