DataService. Чтение записи. Пример
Glossary Item Box
Общие положения
Веб-служба DataService приложения bpm'online является RESTful-сервисом, т.е. поддерживает передачу состояния представления (Representational State Transfer, REST). В общем случае REST является очень простым интерфейсом управления информацией без использования каких-то дополнительных внутренних прослоек, т.е. данные не нужно преобразовывать в какой-либо сторонний формат, например, XML. В простом RESTful-сервисе каждая единица информации однозначно определяется глобальным идентификатором, таким как URL. Каждый URL, в свою очередь, имеет строго заданный формат. Однако это не всегда удобно для передачи больших массивов данных.
В DataService данные автоматичеcки могут быть сконфигурированы в различные форматы данных, такие как XML, JSON, HTML, CSV и JSV. Структура данных определяется так называемыми контрактами данных. Полный перечень контрактов данных, используемых службой DataService, изложен в статье "Веб-служба DataService".
Контракт данных SelectQuery
Для чтения записей раздела используется контракт данных SelectQuery. Передача данных запроса в службу DataService осуществляется по HTTP протоколу при помощи POST запроса по следующему URL:
// Формат URL для POST-запроса на чтение данных из DataService. http(s)://[Адрес приложения bpm'online]/[Номер конфигурации]/dataservice/[Формат данных]/reply/SelectQuery // Пример URL для POST-запроса на чтение данных к DataService. http(s)://example.bpmonline.com/0/dataservice/json/reply/SelectQuery
Контракт данных SelectQuery имеет сложную иерархическую структуру с несколькими уровнями вложенности. В серверной части ядра приложения bpm'online он представлен классом SelectQuery пространства имен Terrasoft.Nui.ServiceModel.DataContract библиотеки классов Terrasoft.Nui.ServiceModel.dll. Для простоты восприятия иерархическую структуру контракта данных SelectQuery удобно представить в формате объекта JSON:
{ "RootSchemaName":"[Имя корневой схемы объекта]", "OperationType":[Тип операции с записью], "Columns":{ "Items":{ "Name":{ "OrderDirection":[Порядок сортировки], "OrderPosition":[Позиция колонки], "Caption":"[Заголовок]", "Expression":{ "ExpressionType":[Тип выражения], "ColumnPath":"[Путь к колонке]", "Parameter":[Параметр], "FunctionType":[Тип функции], "MacrosType":[Тип макроса], "FunctionArgument":[Аргумент функции], "DatePartType":[Тип части даты], "AggregationType":[Тип агрегации], "AggregationEvalType":[Область применения агрегации], "SubFilters":[Вложенные фильтры] } } } }, "AllColumns":[Признак выбора всех колонок], "ServerESQCacheParameters":{ "CacheLevel":[Уровень кеширования], "CacheGroup":[Группа кеширования], "CacheItemName":[Ключ записи в хранилище] }, "IsPageable":[Признак разбиения на страницы], "IsDistinct":[Признак уникальности], "RowCount":[Количество выбираемых записей], "ConditionalValues":[Условия для построения постраничного запроса], "IsHierarchical":[Признак иерархической выборки данных], "HierarchicalMaxDepth":[Максимальный уровень вложенности иерархического запроса], "HierarchicalColumnName":[Имя колонки, использующейся для построения иерархического запроса], "HierarchicalColumnValue":[Начальное значение иерархической колонки], "Filters":[Фильтры] } }
Основные свойства класса SelectQuery и их возможные значения представлены в таблице 1.
Табл. 1. — Свойства класса SelectQuery
Свойство | Тип | Описание | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
RootSchemaName | string | Строка, содержащая название корневой схемы объекта добавляемой записи. | ||||||||||
OperationType | QueryOperationType |
Тип операции с записью. Задается значением перечисления QueryOperationType пространства имен Terrasoft.Nui.ServiceModel.DataContract. Для SelectQuery устанавливается значение QueryOperationType.Select. Значения перечисления QueryOperationType:
|
||||||||||
Columns | SelectQueryColumns | Содержит коллекцию колонок для считываемых записей. Имеет тип SelectQueryColumns, определенный в пространстве имен Terrasoft.Nui.ServiceModel.DataContract. Следует конфигурировать, если значение признака AllColumns установлено как false и нужен определенный набор колонок корневой схемы, не включающий колонку [Id]. | ||||||||||
AllColumns | bool | Признак выбора всех колонок. Если значение установлено как true, в результате выполнения запроса будут выбраны все колонки корневой схемы. | ||||||||||
ServerESQCache |
ServerESQCache |
Параметры кэширования EntitySchemaQuery на сервере. Тип ServerESQCacheParameters определен в пространстве имен Terrasoft.Nui.ServiceModel.DataContract. | ||||||||||
IsPageable | bool | Признак постраничной выборки данных. | ||||||||||
IsDistinct | bool | Признак, указывающий, убирать или нет дубли в результирующем наборе данных. | ||||||||||
RowCount | int | Количество выбираемых строк. По умолчанию содержит значение -1, т.е. выбираются все строки . | ||||||||||
ConditionalValues | ColumnValues | Условия для построения постраничного запроса. Тип ColumnValues определен в пространстве имен Terrasoft.Nui.ServiceModel.DataContract. | ||||||||||
IsHierarchical | bool | Признак иерархической выборки данных. | ||||||||||
HierarchicalMaxDepth | int | Максимальный уровень вложенности иерархического запроса. | ||||||||||
hierarchicalColumnName | string | Имя колонки, использующейся для построения иерархического запроса. | ||||||||||
hierarchicalColumnValue | string | Начальное значение иерархической колонки, от которого будет строиться иерархия. | ||||||||||
Filters | Filters | Коллекция фильтров запросов. Имеет тип Filters, определенный в пространстве имен Terrasoft.Nui.ServiceModel.DataContract. | ||||||||||
ColumnValues | ColumnValues | Содержит коллекцию значений колонок добавляемой записи. Имеет тип ColumnValues, определенный в пространстве имен Terrasoft.Nui.ServiceModel.DataContract. |
Класс SelectQueryColumns имеет единственное свойство Items, которое определено как коллекция ключей и значений Dictionary<string, SelectQueryColumn>. Ключом является строка с названием добавляемой колонки, а значением — экземпляр класса SelectQueryColumn, который определен в пространстве имен Terrasoft.Nui.ServiceModel.DataContract. Свойства класса SelectQueryColumn приведены в табл. 2.
Табл. 2. — Свойства класса SelectQueryColumn
Свойство | Тип | Описание |
---|---|---|
OrderDirection | OrderDirection | Направление сортировки. Задается значением перечисления OrderDirection пространства имен Terrasoft.Common, определенного в библиотеке классов Terrasoft.Common. |
OrderPosition | int | Задает номер позиции в коллекции колонок запроса, по которой производится сортировка. |
Caption | string | Заголовок колонки. |
Expression | ColumnExpression | Свойство, определяющее выражение типа выбираемой колонки. |
Класс ColumnExpression определяет выражение, задающее тип колонки схемы. Он определен в пространстве имен Terrasoft.Nui.ServiceModel.DataContract библиотеки Terrasoft.Nui.ServiceModel. Свойства экземпляра этого класса заполняются в зависимости от свойства ExpressionType, которое и задает тип выражения. Полный перечень свойств класса ColumnExpression приведен в табл. 3.
Табл. 3. — Основные свойства класса ColumnExpression
Свойство | Тип | Описание | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ExpressionType | EntitySchemaQuery |
Тип выражения, определяющий значение, которое будет содержаться в добавляемой колонке. Задается значением перечисления EntitySchemaQueryExpressionType пространства имен Terrasoft.Core.Entities, определенного в библиотеке классов Terrasoft.Core. Для InsertQuery устанавливается значение EntitySchemaQueryExpressionType.Parameter. Значения перечисления EntitySchemaQueryExpressionType:
|
||||||||||||||||||||||||
ColumnPath | string | Путь к колонке относительно корневой схемы. Правила построения путей см. в статье "Использование EntitySchemaQuery для построения запросов к базе данных". | ||||||||||||||||||||||||
Parameter | Parameter |
Определяет значение, которое будет содержаться в добавляемой колонке. Имеет тип Parameter, определенный в пространстве имен Terrasoft.Nui.ServiceModel.DataContract. |
||||||||||||||||||||||||
FunctionType | FunctionType |
Тип функции. Задается значением из перечисления FunctionType, определенного в пространстве имен Terrasoft.Nui.ServiceModel.DataContract. Значения перечисления FunctionType:
|
||||||||||||||||||||||||
MacrosType | EntitySchemaQuery |
Тип макроса. Задается значением перечисления EntitySchemaQueryMacrosType, определенного в пространстве имен Terrasoft.Core.Entities. |
||||||||||||||||||||||||
FunctionArgument | BaseExpression | Аргумент функции. Принимает значение, если функция определена с параметром. Класс BaseExpression определен в пространстве имен Terrasoft.Nui.ServiceModel.DataContract, является предком для класса ColumnExpresion и имеет такой же набор свойств. | ||||||||||||||||||||||||
DatePartType | DatePart |
Часть даты. Задается значением из перечисления DatePart, определенного в пространстве имен Terrasoft.Nui.ServiceModel.DataContract. Значения перечисления DatePart:
|
||||||||||||||||||||||||
AggregationType |
AggregationType | Тип агрегирующей функции. Задается значением из перечисления AggregationType, определенного в пространстве имен Terrasoft.Common, определенного в библиотеке классов Terrasoft.Common. | ||||||||||||||||||||||||
AggregationEvalType | AggregationEvalType | Область применения агрегирующей функции. Задается значением из перечисления AggregationEvalType, определенного в пространстве имен Terrasoft.Core.DB, определенного в библиотеке классов Terrasoft.Core. | ||||||||||||||||||||||||
SubFilters | Filters | Коллекция фильтров вложенных запросов. Имеет тип Filters, определенный в пространстве имен Terrasoft.Nui.ServiceModel.DataContract. |
Класс Parameter определен в пространстве имен Terrasoft.Nui.ServiceModel.DataContract. Его свойства приведены в табл. 4.
Табл. 4. — Свойства класса Parameter
Свойство | Тип | Описание | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
DataValueType | DataValueType |
Тип данных значения, которое будет содержаться в добавляемой колонке. Задается значением перечисления DataValueType пространства имен Terrasoft.Nui.ServiceModel.DataContract Значения перечисления DataValueType:
|
||||||||||||||||||||||||||||||||
Value | object |
Объект, содержащий значение добавляемой колонки. |
||||||||||||||||||||||||||||||||
ArrayValue | string[] |
Массив значений добавляемой колонки. Используется при сериализации массивов и BLOB данных. |
||||||||||||||||||||||||||||||||
ShouldSkipConvertion |
bool |
Признак, отображающий необходимость пропустить процесс приведения типа для свойства Value. |
Класс ServerESQCacheParameters определен в пространстве имен Terrasoft.Nui.ServiceModel.DataContract. Его свойства приведены в табл. 5.
Табл. 5. — Свойства класса ServerESQCacheParameters
Свойство | Тип | Описание |
---|---|---|
CacheLevel | int |
Уровень размещения данных в кэше EntitySchemaQuery. |
CacheGroup | string |
Группа кэширования. |
CacheItemName | string |
Ключ записи в хранилище. |
Класс Filters определен в пространстве имен Terrasoft.Nui.ServiceModel.DataContract. Подробности о свойствах этого класса и пример его использования изложены в статье "DataService. Фильтрация данных".
Пример чтения записей в стороннем приложении
Описание кейса
Необходимо создать консольное приложение, которое, используя службу DataService, прочитает записи раздела [Контакт] со следующими колонками:
- Id;
- ФИО;
- Количество активностей — агрегирующая колонка, отображающая количество активностей данного контакта.
Пример реализации
Полностью исходный код выполнения данного примера можно посмотреть в репозитории GitHub здесь.
Алгоритм реализации кейса
1. Создать и настроить проект консольного приложения C#
Используя среду разработки Microsoft Visual Studio (версии не ниже 2017), необходимо создать проект консольного приложения Visual C#, указав в качестве названия проекта, например, DataServiceSelectExample. Свойству проекта [Target framework] необходимо установить значение .NET Framework 4.7.
В секцию References проекта нужно добавить зависимости от следующих библиотек:
- System.Web.Extensions.dll — библиотека классов, входящая в .NET Farmework;
- Terrasoft.Core.dll — библиотека основных классов серверного ядра приложения. Можно найти по следующему пути: [Каталог с установленным приложением]\Terrasoft.WebApp\bin\Terrasoft.Core.dll;
- Terrasoft.Nui.ServiceModel.dll — библиотека классов служб приложения. Можно найти по следующему пути: [Каталог с установленным приложением]\Terrasoft.WebApp\bin\Terrasoft.Nui.ServiceModel.dll;
- Terrasoft.Common.dll — библиотека основных классов серверного ядра приложения. Можно найти по следующему пути: [Каталог с установленным приложением]\Terrasoft.WebApp\bin\Terrasoft.Common.dll.
В файл исходного кода приложения необходимо добавить директивы using:
using System; using System.Text; using System.IO; using System.Net; using System.Collections.Generic; using Terrasoft.Nui.ServiceModel.DataContract; using Terrasoft.Core.Entities; using System.Web.Script.Serialization; using Terrasoft.Common;
2. В исходный код приложения добавить объявления полей и констант
Для доступа к возможностям службы DataService в исходный код приложения необходимо добавить следующие поля и константы:
// Основной URL приложения bpm'online. Необходимо заменить на пользовательский. private const string baseUri = @"http://example.bpmonline.com"; // Строка запроса к методу Login сервиса AuthService.svc. private const string authServiceUri = baseUri + @"/ServiceModel/AuthService.svc/Login"; // Строка пути запроса SelectQuery. private const string selectQueryUri = baseUri + @"/0/DataService/json/SyncReply/SelectQuery"; // Cookie аутентификации bpm'online. private static CookieContainer AuthCookie = new CookieContainer();
Здесь объявлены три строковых константных поля, с помощью которых формируются пути выполнения запросов на аутентификацию и запросов на чтение данных. Данные об аутентификации будут сохранены в поле AuthCookie.
3. Добавить метод, выполняющий аутентификацию в приложении bpm'online
Для доступа создаваемого приложения к веб-службе DataService необходимо выполнить аутентификацию.
Алгоритм действия и пример реализации метода, который выполняет запрос к службе AuthService.svc для аутентификации пользователя, подробно изложены в статье Аутентификация внешних запросов к веб-сервисам bpm'online.
4. Добавить непосредственную реализацию запроса на добавление записи
Поскольку объявленная ранее константа selectQueryUri содержит путь для отправки данных в формате JSON, то отправляемые данные нужно предварительно сконфигурировать в виде строки, содержащей описание JSON-объекта, соответствующего контракту данных SelectQuery. Это можно сделать непосредственно в некоторой строчной переменной, однако намного удобнее и безопаснее с точки зрения возможности возникновения ошибок — создать экземпляр класса SelectQuery, заполнить его свойства, а затем сериализовать его в строку. Сделать это можно, добавив следующий исходный код:
// Экземпляр класса запроса. var selectQuery = new SelectQuery() { // Название корневой схемы. RootSchemaName = "Contact", // Коллекция колонок запроса. Columns = new SelectQueryColumns() }; // Выражение, задающее тип колонки [[ФИО]. var columnExpressionName = new ColumnExpression() { // Тип выражения — колонка схемы. ExpressionType = EntitySchemaQueryExpressionType.SchemaColumn, // Путь к колонке. ColumnPath = "Name" }; // Конфигурирование колонки [Name]. var selectQueryColumnName = new SelectQueryColumn() { //Заголовок. Caption = "ФИО", // Направление сортировки — по возрастанию. OrderDirection = OrderDirection.Ascending, // Позиция порядка сортировки. OrderPosition = 0, // Выражение, задающее тип колонки. Expression = columnExpressionName }; // Выражение, задающее тип колонки [Количество активностей]. var columnExpressionActivitiesCount = new ColumnExpression() { // Тип выражения — вложенный запрос. ExpressionType = EntitySchemaQueryExpressionType.SubQuery, // Путь к колонке относительно корневой схемы. ColumnPath = "[Activity:Contact].Id", // Тип функции — агрегирующая. FunctionType = FunctionType.Aggregation, // Тип агрегации — количество. AggregationType = AggregationType.Count }; // Конфигурирование колонки [Количество активностей]. var selectQueryColumnActivitiesCount = new SelectQueryColumn() { //Заголовок. Caption = "Количество активностей", // Направление сортировки — по возрастанию. OrderDirection = OrderDirection.Ascending, // Позиция порядка сортировки. OrderPosition = 1, // Выражение, задающее тип колонки. Expression = columnExpressionActivitiesCount }; // Добавление колонок в запрос. selectQuery.Columns.Items = new Dictionary<string, SelectQueryColumn>() { { "Name", selectQueryColumnName }, { "ActivitiesCount", selectQueryColumnActivitiesCount } }; // Сериализация экземпляра класса запроса на добавление в JSON-строку. var json = new JavaScriptSerializer().Serialize(selectQuery);
На завершающем шаге необходимо выполнить POST-запрос к службе DataService. Для этого необходимо создать экземпляр класса HttpWebRequest, заполнить его свойства, присоединить к запросу созданную ранее строку с JSON-объектом, а затем выполнить и обработать результат запроса к службе DataService. Для этого нужно добавить следующий исходный код:
// Преобразование строки JSON-объекта в массив байтов. byte[] jsonArray = Encoding.UTF8.GetBytes(json); // Создание экземпляра HTTP-запроса. var selectRequest = HttpWebRequest.Create(selectQueryUri) as HttpWebRequest; // Определение метода запроса. selectRequest.Method = "POST"; // Определение типа содержимого запроса. selectRequest.ContentType = "application/json"; // Добавление полученных ранее аутентификационных cookie в запрос на получение данных. selectRequest.CookieContainer = AuthCookie; // Установить длину содержимого запроса. selectRequest.ContentLength = jsonArray.Length; // Добавление CSRF токена в заголовок запроса. CookieCollection cookieCollection = AuthCookie.GetCookies(new Uri(authServiceUri)); string csrfToken = cookieCollection["BPMCSRF"].Value; selectRequest.Headers.Add("BPMCSRF", csrfToken); // Помещение JSON-объекта в содержимое запроса . using (var requestStream = selectRequest.GetRequestStream()) { requestStream.Write(jsonArray, 0, jsonArray.Length); } // Выполнение HTTP-запроса и получение ответа от сервера. using (var response = (HttpWebResponse)selectRequest.GetResponse()) { // Вывод ответа в консоль. using (StreamReader reader = new StreamReader(response.GetResponseStream())) { Console.WriteLine(reader.ReadToEnd()); } }
Полностью исходный код выполнения данного примера можно посмотреть в репозитории GitHub здесь.
Пример чтения записей в приложении bpm'online
Описание кейса
Добавить в раздел [Контакты] кнопку при нажатии на которую вызывается метод, который, используя службу DataService, прочитает записи раздела [Контакты] со следующими колонками:
- Id;
- ФИО;
- Количество активностей — агрегирующая колонка, отображающая количество активностей данного контакта.
Пример реализации
Полностью исходный код выполнения данного примера можно скачать здесь.
Алгоритм реализации кейса
1. Добавить в раздел [Контакты] кнопку
Процесс добавления кнопки в раздел подробно описан в статье "Добавление кнопки в раздел".
Для рассматриваемого кейса необходимо создать замещающий клиентский модуль раздела [Контакты] (рис. 1).
Рис. 1. — Свойства замещающего клиентского модуля
В созданной клиентской схеме добавить локализуемую строку SelectQueryContactButtonCaption, для которой установить значение "Выбор контактов" (рис. 2).
Рис. 2. — Свойства локализуемой строки
В массив diff добавить конфигурационный объект с настройками расположения кнопки на странице.
//Настройка визуализации кнопки в разделе. diff: /**SCHEMA_DIFF*/[ // Метаданные для добавления в раздел пользовательской кнопки. { // Указывает на то, что выполняется операция добавления элемента на страницу. "operation": "insert", // Мета-имя родительского элемента управления, в который добавляется кнопка. "parentName": "ActionButtonsContainer", // Указывает на то, что кнопка добавляется в коллекцию элементов управления // родительского элемента (мета-имя которого указано в parentName). "propertyName": "items", // Мета-имя добавляемой кнопки. "name": "SelectQueryContactButton", // Дополнительные свойства элемента. "values": { // Тип добавляемого элемента — кнопка. itemType: Terrasoft.ViewItemType.BUTTON, // Привязка заголовка кнопки к локализуемой строке схемы. caption: { bindTo: "Resources.Strings.SelectQueryContactButtonCaption" }, // Привязка метода-обработчика нажатия кнопки. click: { bindTo: "onSelectQueryContactClick" }, "layout": { "column": 1, "row": 6, "colSpan": 1 } } } ]/**SCHEMA_DIFF*/
2. Добавить метод-обработчик события нажатия кнопки
Для того чтобы при нажатии на созданную в разделе кнопку читались записи с необходимыми данными, в секцию methods замещающей клиентской схемы необходимо добавить следующий метод:
methods: { // Метод-обработчик нажатия кнопки. onSelectQueryContactClick: function() { // Создание экземпляра класса Terrasoft.InsertQuery. var select = Ext.create("Terrasoft.EntitySchemaQuery", { // Название корневой схемы. rootSchemaName: "Contact" }); // Добавление в запрос колонки [ФИО]. select.addColumn("Name"); // Добавление в запрос агрегирующей колонки [Количество активностей]. select.addAggregationSchemaColumn( // Путь к колонке относительно корневой схемы. "[Activity:Contact].Id", // Тип агрегации — количество. Terrasoft.AggregationType.COUNT, // Заголовок колонки. "ActivitiesCount", // Область применения агрегирующей функции — для всех элементов. Terrasoft.AggregationEvalType.ALL); // Запрос к серверу на обновление данных // Получение всей коллекции записей и ее отображение в консоли браузера. select.getEntityCollection(function(result) { if (!result.success) { // Обработка/логирование ошибки. this.showInformationDialog("Ошибка запроса данных"); return; } // Выводимое сообщение. var message = ""; // Перебор результирующей коллекции и построение выводимого сообщения. result.collection.each(function(item) { message += "ФИО: " + item.get("Name") + ". Количество активностей: " + item.get("ActivitiesCount") + "\n"; }); // Вывод сообщения в консоль. window.console.log(message); }, this); } }
К СВЕДЕНИЮ В отличие от предыдущего примера, авторизация не требуеся, поскольку программный код выполняется непосредственно в приложении bpm'online. |
В клиентской части ядра приложения отсутствует класс, аналогичный классу SelectQuery в серверной части ядра. Для выбора данных некоторого раздела необходимо использовать класс Terrasoft.EntitySchemaQuery. Подробнее о свойствах и методах этого класса можно узнасть из статьи "Использование EntitySchemaQuery для чтения данных из БД" или в документации по API здесь.
Полностью исходный код выполнения данного примера можно скачать здесь.