Доброго времени суток! Коллеги, помогите пожалуйста с переводом запроса SQL на С# для использования в конфигурационном веб-сервисе. Необходимо через запрос к веб-сервису по ИНН контакта получать в ответе перечень Id заявок и Названий их статусов. SQL запрос выглядит так:

 

SELECT a.Id, s.Name
FROM dbo.Application a
INNER JOIN dbo.Contact c ON a.ContactId = c.Id
INNER JOIN dbo.AppStatus s ON a.StatusId = s.Id
WHERE c.INNN='1234567890'

 

Нравится

15 комментариев

Здравствуйте! В данной статье описано как работать с классом EntitySchemaQuery и как строить пути к колонкам, а в данной статье показано как получить данные из запроса.

Сделал согласно информации в указанных статьях:

        public string UsrGetAppInfoByINN(string INN) {
            // Результат по умолчанию.
            var result = "";
            // Экземпляр EntitySchemaQuery, обращающийся в таблицу Application базы данных.
            var esqQuery = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "Application");
            // Добавление колонок в запрос.
            esqQuery.AddColumn("Id");
            esqQuery.AddColumn("[AppStatus:Id:StatusId].Name");
            esqQuery.AddColumn("[Contact:Id:ContactId].INN");
               // Фильтрация данных запроса.
            var esqFilter = esq.CreateFilterWithParameters(FilterComparisonType.Equal, "INN", INN);
            esq.Filters.Add(esqFilter);
            // Получение результата запроса.
            string esqSqlText = esqQuery.GetSelectQuery(UserConnection).GetSqlText(); 
            // Возвратить результат.
            return result;

При публикации получаю ошибки "The name 'esq' does not exist in current context в строках:   

            var esqFilter = esq.CreateFilterWithParameters(FilterComparisonType.Equal, "INN", INN);
            esq.Filters.Add(esqFilter);

            esq.Filters.Add(esqFilter);

Так у Вас переменная называется esqQuery, а не esq.

Зверев Александр,

заменил esq на esqQuery. Схема публикуется, но на запрос приходит ошибка: 

The server encountered an error processing the request. The exception message is 'Элемент коллекции с именем StatusId не найден'. 

Если убрать эту строку из кода - ругается на следующую ContactId, хотя обе эти колонки есть в таблице Application

        public string UsrGetAppInfoByContactINN(string INN) {
            // Результат по умолчанию.
            var result = "";
            // Экземпляр EntitySchemaQuery, обращающийся в таблицу Application базы данных.
            var esqQuery = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "Application");
            // Добавление колонок в запрос.
            esqQuery.AddColumn("INN");
            esqQuery.AddColumn("[AppStatus:Id:StatusId].Name");
            esqQuery.AddColumn("[Contact:Id:ContactId].INN");
               // Фильтрация данных запроса.
            var esqFilter = esqQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "INN", INN);
            esqQuery.Filters.Add(esqFilter);
            // Получение результата запроса.
            string esqSqlText = esqQuery.GetSelectQuery(UserConnection).GetSqlText(); 
            // Возвратить результат.
            return result;

Что я делаю не так?

Нужно писать названия полей без Id, см. примеры по ссылке выше.

Зверев Александр,

не понимаю почему без Id, если колонки в таблице так и называются: ContactId, StatusId, но это помогло, спасибо.

 

Правда теперь после отправки запроса - я получаю пустой ответ на запрос:

{"UsrGetAppInfoByContactINN":""}

 

Александр О,

здравствуйте! Далее Вам необходимо получить коллекцию

var collection = esqQuery.GetEntityCollection(UserConnection);
if(collection.Count > 0)
{
  foreach(var entity in collection)
  {
     var name = entity.GetTypedColumnValue<string>("Name");
  }
}

 Примерно так.

Только еще один момент, Вам необходимо получить названия колонок  в esqQuery, что бы потом можно было выбирать из коллекции по имени.

var appColName = esqQuery.AddColumn("[AppStatus:Id:StatusId].Name").Name;
 
var collection = esqQuery.GetEntityCollection(UserConnection);
if(collection.Count > 0)
{
  foreach(var entity in collection)
  {
     var name = entity.GetTypedColumnValue<string>(appColName);
  }
}

 

Александр О пишет:
не понимаю почему без Id, если колонки в таблице так и называются

Оно в этом случае не пишется, при генерации запроса подставляется автоматически.

Нигрескул Алексей,

с помощью Ваших рекомендаций и дополнительных танцев с бубном схема видоизменилась на:

        public string UsrGetAppInfoByContactSSN(string ContactINN) {
            var result = "";
            var esqQuery = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "Application");
            var appColApplicationId = esqQuery.AddColumn("Id").Name;
            var appColStatus = esqQuery.AddColumn("Status.Name").Name;
            var appColINN = esqQuery.AddColumn("Contact.INN").Name;
            var esqFilter = esqQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Contact.INN", ContactINN);
            esqQuery.Filters.Add(esqFilter);
            var collection = esqQuery.GetEntityCollection(UserConnection);
                if(collection.Count > 0)
                    {
                      foreach(var entity in collection)
                        {
            var name = ("ApplicationId:").ToString() + entity.GetTypedColumnValue<string>(appColApplicationId)
                   +(", Status:").ToString() + entity.GetTypedColumnValue<string>(appColStatus)
                   +(", INN:").ToString() + entity.GetTypedColumnValue<string>(appColINN);
            return name;
                        }
                     }
            return result;

 В результате в ответ на запрос получаю:

{"UsrGetAppInfoByContactSSNResult":"ApplicationId:cee41684-295b-4384-8dfb-1fa3fdd835cc, Status:Підтверджена, INN:4562378478"}

Но это только одна запись.

Что нужно изменить в схеме чтобы в ответе приходили все найденные записи? Например так:

{"UsrGetAppInfoByContactSSNResult":
"ApplicationId:a913e1c5-6e83-428c-b095-0cf1b3aca5bf, Status:Підтверджена, INN:4562378478"
"ApplicationId:cee41684-295b-438e-8dfb-1fa3fdd835cc, Status:В роботі, INN:4562378478"
"ApplicationId:47a7a0be-4c21-430f-9da9-7d1b658cff92, Status:Відмовлено, INN:4562378478"
}

 

Александр О,

здравствуйте! В таком случае я бы сделал так:

public class AppInfoByContactSSN
{
 public Guid ApplicationId {get;set;}
 public string StatusName {get;set;}
 public string Inn {get; set;}
}
 
public List<AppInfoByContactSSN> UsrGetAppInfoByContactSSN(string ContactINN) {
            var result = new List<AppInfoByContactSSN>();
            var esqQuery = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "Application");
            var appColApplicationId = esqQuery.AddColumn("Id").Name;
            var appColStatus = esqQuery.AddColumn("Status.Name").Name;
            var appColINN = esqQuery.AddColumn("Contact.INN").Name;
            var esqFilter = esqQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Contact.INN", ContactINN);
            esqQuery.Filters.Add(esqFilter);
            var collection = esqQuery.GetEntityCollection(UserConnection);
                if(collection.Count > 0)
                {
                      foreach(var entity in collection)
                        {
                           result.Add(new AppInfoByContactSSN {
					ApplicationId = entity.GetTypedColumnValue<Guid>(appColApplicationId),
					StatusName = entity.GetTypedColumnValue<string>(appColStatus),
					Inn = entity.GetTypedColumnValue<string>(appColINN)
				});
                        }
                 }
 
             return result;  
}

 

Нигрескул Алексей,

пришлось еще добавить в using System.Collections.Generic;

Но при публикации на строку:

public List<AppInfoByContactSSN> UsrGetAppInfoByContactSSN(string ContactINN) {

выдает ошибку: a namespace cannot directly contain members such us fields or methods.

 

Полный код:

namespace Terrasoft.Configuration.UsrCustomNamespace
{
    using System;
    using System.ServiceModel;
    using System.ServiceModel.Web;
    using System.ServiceModel.Activation;
    using Terrasoft.Core;
    using Terrasoft.Web.Common;
    using Terrasoft.Core.Entities;
    using System.Collections.Generic;
 
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
     public class AppInfoByContactSSN
       {
        public Guid ApplicationId {get;set;}
        public string StatusName {get;set;}
        public string Inn {get; set;}
       }
 
        [OperationContract]
        [WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
        ResponseFormat = WebMessageFormat.Json)]
 
        public List<AppInfoByContactSSN> UsrGetAppInfoByContactSSN(string ContactINN) {
            var result = new List<AppInfoByContactSSN>();
            var esqQuery = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "Application");
            var appColApplicationId = esqQuery.AddColumn("Id").Name;
            var appColStatus = esqQuery.AddColumn("Status.Name").Name;
            var appColINN = esqQuery.AddColumn("Contact.INN").Name;
            var esqFilter = esqQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Contact.INN", ContactINN);
            esqQuery.Filters.Add(esqFilter);
            var collection = esqQuery.GetEntityCollection(UserConnection);
             if(collection.Count > 0)
                {
                 foreach(var entity in collection)
                  {
                    result.Add(new AppInfoByContactSSN {
                    ApplicationId = entity.GetTypedColumnValue<Guid>(appColApplicationId),
                    StatusName = entity.GetTypedColumnValue<string>(appColStatus),
                    Inn = entity.GetTypedColumnValue<string>(appColINN)
                   });
                  }
                }
            return result;
     }
}

 

Так у Вас метод не внутри класса, а после, потому и ругается. Метод должен быть в классе, а не в окружающем его namespace.

Зверев Александр,

так тоже пробовал, но на строку:

var esqQuery = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "Application");

выдает ошибку:

An object reference is required for t he non-static field, method, or property 'User.Connection.EntitySchemaManager'

 

и на строку:

var collection = esqQuery.GetEntityCollection(UserConnection);

выдает ошибку:

'UserConnection' is a type, which is not valid in the given context

 

Александр, значит, у Вас в переменной UserConnection не то, что должно там быть. Попробуйте поискать в конфигурации или на этом  сайте примеры, как правильно делать. А если выдаёт ошибку, то по её тексту можно найти поиском в Интернете более подробное пояснение, что это означает.

 

Пример создания сервиса есть тут. Как минимум, у Вас не хватает наследования класса от BaseService.

Показать все комментарии

Коллеги, добрый день!

Мне необходимо внести изменения в базовый конфигурационный сервис AdministrationServiceUsers.

Возможно ли создать замещающую схему для сервиса? 

Подскажите, как правильно это сделать? В академии не нашел информации.

Нравится

3 комментария

Добрый день, Павел.

Вносить изменения в базовые веб сервисы нет возможности.

Для этих целей Вам необходимо реализовать собственный веб - сервис,

Вы можете выполнить наследование в своем сервисе от базового, но, так как многие методы нет возможности переопределить, оптимальным решением будет реализовать полностью свой сервис по аналогии с базовым.

Подробно вопрос конфигурирования веб-сервисов рассматривается в видео-обучении. https://www.youtube.com/watch?v=rbdB7LFgNf0&feature=youtu.be

Антон Малий,

а случайно ссылки на "День 2" у Вас нет?

Александр О,

Продвинутая разработка, день 2 (внимание, версия 7.11, многое устарело): https://youtu.be/y45IHGDm0WY

Показать все комментарии

Каким образом можно отладить конфигурационный сервис в bpm'online on-demand?

Нравится

4 комментария

пишите в логи и запрашивайте их с ТП

Ха-ха-ха, Дмитрий - это один из самых "быстрых" способов отладки.

В любом случае, как за один из возможных вариантов решения, спасибо)

Ха-ха-ха, Дмитрий - это один из самых "быстрых" способов отладки.

В любом случае, как за один из возможных вариантов решения, спасибо)

не, ну вы можете осуществить WS-канал между клиентом-сервером, обернуть отлаживаемый код в try-catch и ошибки отсылать на клиент, а на клиенте их обрабатывать и показывать как вам будет удобно, но это слегка тяжеловесно
мб вы не знаете, но в консоле браузера есть вкладка Network (chrome) где можно посмотреть подробно все запросы к серверу и ответы от него. Большинство ошибок с сервера вываливаются туда в читаемом виде. Но это не подходит для фоновых процессов (происходящих вне рамок текущей веб-сессии), в т.ч. БП.

Показать все комментарии

Каким образом можно отладить конфигурационный сервис в bpm'online on-demand?

Нравится

3 комментария

Алла, здравствуйте!

Отладка конфигурационных сервисов, также как и остального C# возможна только в on-site, согласно статье https://academy.terrasoft.ru/documents/technic-sdk/7-7-0/otladka-server…

В облаке использовать такие инструменты возможности нет. Как вариант решения можно запросить базу и дистрибутив в поддержке и развернуть локальную среду разработки, отлаживать и переносить на продуктив после окончания разработки.

"Алла Савельева" написал:Каким образом можно отладить конфигурационный сервис в bpm'online on-demand?

Либо лепить костыли (как в старые добрые):
1) Скачать и установить дополнение "консоль sql запросов"
2) Добавить объект в конфигурацию с 1-2 varchar полями
2) В сервис напихать море try/catch + кучу логгеров в этот самый объект (чтобы писались ошибки/шаги выполнения и т.п.)

"Варфоломеев Данила" написал:
1) Скачать и установить дополнение "консоль sql запросов"
2) Добавить объект в конфигурацию с 1-2 varchar полями
2) В сервис напихать море try/catch + кучу логгеров в этот самый объект (чтобы писались ошибки/шаги выполнения и т.п.)

Здравствуйте!

Первый пункт лишний - можно создать справочник на основании созданного объекта и фильтровать по справочнику. Или выгрузить содержимое в Excel и изучать логи там.

Показать все комментарии

Здравствуйте !

Пожалуйста, подскажите, как решить следующую задачу.

В пользовательском пакете (управление конфигурацией) есть готовый исходный код веб-сервиса UsrSourceCode1. Как бизнес-процессу использовать написанный конфигурационный сервис и передать ему входные параметры?

Например, нужно посчитать сумму счетов по контрагенту. Из схемы раздела "Контрагент" запускается бизнес-процесс, передав входные параметры. В свою очередь, бизнес процесс обращается к сервису для подсчета суммы счетов. В веб-сервисе эта сумма считается, и результаты возвращаются бизнес-процессу.

Версия: bpm'online sales enterprise 7.8

Нравится

3 комментария

Здравствуйте,
Проверю кое-что и отвечу в соседней теме:
http://www.community.terrasoft.ru/forum/topic/24733
Незачем создавать дубли.

Здравствуйте!

Пример вы можете посмотреть в процессе CreateInvoiceFromOrder (Создание счета на основании заказа). В элементе "Задание-сценарий" вызывается метод CreateInvoice(). Этот метод вызывает метод CreateEntity() схемы OrderInvoiceHelper. Создание счета реализовано в схеме OrderInvoiceHelper.

Спасибо большое за ответ. Буду разбираться. Извините за дубли.

Показать все комментарии

Здравствуйте !

Пожалуйста, подскажите, как решить следующую задачу.
Есть бизнес-процесс UsrProcess1. В пользовательском пакете (управление конфигурацией) есть исходный код веб-сервиса UsrSourceCode1.

Как бизнес-процессу использовать написанный конфигурационный сервис и передать ему входные параметры?

Например, нужно посчитать сумму счетов по контрагенту. В веб-сервисе эта сумма считается, принимая на вход id контрагента. То есть нужно передать бизнес-процессу идентификатор контрагента и запустить сервис.

Нравится

3 комментария

Какая версия?

Здравствуйте.
bpm'online sales enterprise 7.8 пробная

Здравствуйте,
Если сервис создан в той же bpm’online что в БП, то просто можно создать экземпляр класса, и вызвать нужный вам метод. Пример привели в соседней теме, в комментарии:
http://www.community.terrasoft.ru/forum/topic/24735#comment-65599

Показать все комментарии