Описание
В D365O, по сравнению с AX2012, была добавлена возможность подключения к развернутым по-умолчанию веб-сервисам OData. Веб-сервисы этого типа позволяют считывать и модифицировать данные всех data entity D365O, настройки которых позволяют это делать. Считывание данных происходит в формате JSON.
Для считывания данных, клиент отправляет на веб-сервисы GET запросы, в которых указывает то, какие данные из data entity он хочет получить. При этом доступна фильтрация по каждому из полей data entity, в том числе и по полям, входящим в другие поля. Подробно о возможных запросах можно прочитать в документации протокола OData , доступной по следующей ссылке: http://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/part1-protocol/odata-v4.0-errata03-os-part1-protocol-complete.html#_Toc453752278. Далее из всего функционала по работе с data entity через веб-сервисы приведена информация только по фильтрации и выборке выводимых полей.
Базовым запросом к веб-сервисам OData является запрос вида «АДРЕС D365O»/data. Например, https://oit-adm-boryseda2b5401719f08ddevaos.cloudax.dynamics.com/data. При этом возвращается список названий всех data entity в D365O. При чем, выведенные названия – это не названия файлов data entity в AOT, а PublicCollectionName, указанные в параметрах этих файлов.
При добавлении к базовому запросу названия одной из data entity указаных в списке (запрос вида «АДРЕС D365O»/data/«НАЗВАНИЕ DATA ENTITY»), выводятся все значения, содержащиеся в data entity, у которых компания соответствует компании пользователя, под чьей учетной записью был получен доступ к веб-сервису. Например: https://oit-adm-boryseda2b5401719f08ddevaos.cloudax.dynamics.com/data/ReleasedProductMasters.
Для получения данных всех компаний, необходимо добавить параметр cross-company=true: «АДРЕС D365O»/data/«НАЗВАНИЕ DATA ENTITY»?cross-company=true. Например: https://oit-adm-boryseda2b5401719f08ddevaos.cloudax.dynamics.com/data/ReleasedProductMasters?cross-company=true.
Для получения данных по конкретной компании, помимо указания cross-company=true, необходимо использовать фильтрацию.
Фильтрация в протоколе OData осуществляется с помощью добавления к строке URL параметра $filter=. После знака равенства указываются все условия фильтрации. При построении условий фильтрации могут использоваться следующие операторы:
Операторы сравнения:
Логические операторы:
Арифметические операторы:
Операторы группировки: ().
Самый простые условия выглядят так: «НАЗВАНИЕ ПОЛЯ» «ОПЕРАТОР СРАВНЕНИЯ» «ЗНАЧЕНИЕ» «ЛОГИЧЕСКИЙ ОПЕРАТОР» «НАЗВАНИЕ ПОЛЯ» «ОПЕРАТОР СРАВНЕНИЯ» «ЗНАЧЕНИЕ». Например, добавив условия фильтрации к указанному раннее URL, получаем: https://oit-adm-boryseda2b5401719f08ddevaos.cloudax.dynamics.com/data/ReleasedProductMasters?cross-company=true&$filter=ItemNumber eq ‘M0008’ and BOMLevel eq 0 and dataAreaId eq ‘USMF’. Как видно, последнее из полей в даной строке – dataAreaId, которое отвечает за выбор компании.
При фильтрации по текстовым полям, нужно использовать одинарные кавычки ‘ ’ вокруг значения.
При фильтрации по числовым полям, значение записывается без кавычек.
При фильтрации по значению enum полей, используется синтаксис вида: «NAMESPACE, К КОТОРОМУ ОТНОСИТСЯ ENUM».«НАЗВАНИЕ ENUM»’«ЗНАЧЕНИЕ ENUM»’. Например, значение может выглядеть следующим образом: System.Web.OData.TestCommon.Models.Gender’Male’.
Стоит отметить, что при переходе в браузере по URL, в котором указаны условия фильтрации, вид этого URL изменяется, заменяя символы пробела на %20, а символы одинарных кавычек на %27. Волноваться по этому поводу не нужно, — можно даже комбинировать в запросе указанные выше обозначения этих знаков и их нормальное обозначение, при этом запрос должен отработать корректно.
Описанные выше условия отфильтровывают результат, идущий на выход сервиса, но при этом клиентская программа все еще получает все поля, относящиеся к оставшимся после фильтрации data entity. Чтобы указать, какие конкретно поля нужно возвращать, в запросе URL используется параметр $select=. После знака равенства необходимо через запятую, слитно, перечислить необходимые поля. Например: $select=ItemNumber,BOMLevel.
Таким образом, запрос для одновременной фильтрации и выборки выглядит, например, следующим образом: https://oit-adm-boryseda2b5401719f08ddevaos.cloudax.dynamics.com/data/ReleasedProductMasters?cross-company=true&$select=ItemNumber,BOMLevel,dataAreaId&$filter=ItemNumber eq ’M0008’ and BOMLevel eq 0.
При возникновении необходимости в формировании более сложных запросов, рекомендую ознакомиться с документацией. OData поддерживает большой набор встроенных функций, — от обрезки строк до математических округлений и выделения лет, месяцев, дней и времени из дат.
На выходе OData вебсервисов D365O используется JSON следующей структуры:
Подготовительный этап
При использовании вспомогательного проекта JsonRequestSender, вызов вебсервиса сводится к одной команде. Для этого сначала нужно создать объект класса RequestSender_OAuth, так как в вебсервисах D365O используется аутентификация OAuth.
Далее, так как считать данные из OData вебсервисов D365O можно с помощью GET запросов, отправляем GET запрос, по правилам запросов OData.
В метод sendGETRequest() передаются один дженерик класс и один аргумент.
Дженерик класс определяет то, объект какого класса должен использоваться в качестве выходного контракта с данными в вебсервисе.
Аргумент определяет относительный адрес вызываемого метода вебсервиса в ресурсе. В данном случае относительный адрес показывает, что нужно вернуть записи из data entity с PublicCollectionName GoalHeadings, по всем компаниям.
Пример
В качестве примера приведено приложение Microsoft forms для получения данных из data entity HcmGoalHeadingEntity D365O.
Основной код
Класс сервиса
Не зависимо от того, нужно ли найти, создать, обновить или удалить запись в data entity, первым делом нужно создать класс, наследующий вспомогательный класс ODataServiceBase из проекта ODataProxy. Например:
Все операции должны быть объявлены в этом классе, так как он настроен на работу со всеми data entity системы, к которой нужно подключиться.
Для создания новой записи, создается и заполняется значениями объект нужной data entity из прокси класса. При этом нужно заполнить все обязательные поля data entity.
Далее у OData клиента, созданного на основе прокси класса, вызывается метод AddObject, в котором первым параметром передается PublicCollectionName data entity, а вторым – переменная контракта данных data entity.
После этого запрос отправляется на сервер, желательно в try-catch:
Для считывания данных по data entity нужно выполнить Linq запрос для выбранной в переменной клиента data entity.
При этом результат нужно преобразовать в DataServiceCollection для корректной отработки операции обновления. Это позволит клиенту отправлять PATCH запросы вместо PUT для обновления данных, что предотвратит ошибки при наличии в data entity закрытых на редактирование полей.
Запрос лучше отправлять в try-catch.
Рассмотрим часть Linq запроса:
Этот запрос означает, что из клиента OData вызывается считывание данных по data entity с PublicCollectionName PurchaseOrderHeadersV2, и при этом должны вернутся такие записи, у которых поле PurchaseOrderNumber соответствует некоторой переменной purchId, или же записи вне зависимости от PurchaseOrderNumber, если переменная purchId содержит пустую строку.
Таким образом можно отфильтровать результат по любым полям data entity.
Вне зависимости от того, преобразовывался ли результат запроса в рекомендуемый класс DataServiceCollection, по полученным значениям можно пройти с помощью цикла foreach.
Изменение данных
Для изменения данных data entity, их сначала нужно получить. То есть, сначала необходимо выполнить все шаги описанные в инструкции по считыванию данных.
Далее нужно изменить некоторые поля.
После этого запрос отправляется на сервер, желательно в блоке try-catch:
Удаление данных
Для удаления данных data entity, их сначала нужно получить. То есть, сначала необходимо выполнить все шаги описанные в инструкции по считыванию данных.
Далее для указания OData клиенту того, что data entity должна быть удалена при выполнении запроса, вызывается метод DeleteObject, в который передается полученная переменная контракта данных data entity.
После этого запрос отправляется на сервер, желательно в блоке try-catch:
Пример
В качестве примера приведено приложение Microsoft forms для получения, создания, обновления и удаления данных из data entity PurchPurchaseOrderHeaderV2Entity D365O.
В случае получения данных, поля над кнопками служат фильтрами и не обязательны для заполнения.
Для создания новых записей и для обновления существующих все поля должны быть заполнены. При этом при обновлении будет найдена запись с указанным Purch id и все остальные ее поля будут обновлены.
Для удаления записи достаточно указать ее Purch id.