Подскажите пожалуйста как можно настроить тестовые данные, для того что бы протестировать Delete с помощью библиотеки Terrasoft.TestFramework?

Может у вас есть пример кода?
Спасибо.

Нравится

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

Александр, для создания записей, как и везде в скриптах, можно воспользоваться функциональностью классов либо Entity, либо Insert, иногда используют их совместно, как в функциях, которые применялась для подготовки тестирования работоспособности Delete в ядре:

  public static void CreateSchemaDataInDB(UserConnection userConnection, EntitySchema entitySchema,
    params object[] values) {
   Entity entity = entitySchema.CreateEntity(userConnection);
   int columnIndex = 0;
   foreach (object value in values) {
    entity.SetColumnValue(entitySchema.Columns[columnIndex++], value);
   }
   var insert = entity.CreateInsert();
   insert.Execute();
  }
 
  public static void CreateSchemaDataInDB(UserConnection userConnection, EntitySchema entitySchema,
    TestData testData) {
   var inserts = new Collection<Insert>();
   foreach (var dataRow in testData) {
    Entity entity = entitySchema.CreateEntity(userConnection);
    foreach (TestDataColumnValue dataColumn in dataRow) {
     entity.SetColumnValue(dataColumn.GetColumnValueName(), dataColumn.Value);
    }
    inserts.Add(entity.CreateInsert());
   }
   using (DBExecutor dbExecutor = userConnection.EnsureDBConnection()) {
    foreach (Insert item in inserts) {
     item.Execute(dbExecutor);
    }
   }
  }

Но конкретная реализация зависит от того, что Вы хотите создавать и удалять в ходе своего теста.

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

А возможно не создавать реально данные в базе? а использовать какое-то темповое хранилище?? Или что бы проверить Delete мне необходимо создавать реальные данные в базе?? и Как в таком случае в тестах инициализировать UserConnection?

Спасибо.

В этой теме есть примеры как имитации данных в базе, так и с формированием реальных запросов, но без их запуска, со сравнением полученного SQL-кода. Там тестируют Select, можно так и с Delete.

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

 

Я видел эту тему, но код который используется в нем у меня не компилируется так как не видно некоторых типов

TestDBTypeConverter
TestData
TestData testData = UnitTestUtilities.GetTestDataWithStructure(entitySchemaManager, "Activity");

Не могу понять какую библиотеку нужно подключить для корректной работы??

у меня версия системы 7.12.2

 

В 7.12 уже должны работать примеры из этой статьи, там есть ссылка на исходники SDK.

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

Как я могу передать строковый спец символ вместе с ссылкой?

Добрый день, когда передаю строку вида, которая содержит ссылку
xmlns:xs= \"http://www.w3.org/2001/XMLSchema\"
то на выходе я получаю \"www.w3.org/2001/XMLSchema", без последнего символа \, с строками отличными от данной все работает нормально
Вот последняя версия , с которой я пытаюсь произвести замену
historyContactInfo = historyContactInfo.Replace(@"\r\n", string.Empty).Replace(@"\", string.Empty).Replace("\"",@" \" +"\"");
 

Пробуя подобное на .net Framework все формируется нормально
Также я пробовал делать замену с помощью символа &quot, все равно не пропускает

Нравится

1 комментарий

Опишите более подробно, что делаете, что хотели и что вышло.

В системе серверный код компилируется под тот же  .net Framework или .net Core компилятором от Microsoft, отличий быть не должно.

 

Как работать с этим символом, см. тут:

The backslash ("\") character is a special escape character used to indicate other special characters such as new lines (\n), tabs (\t), or quotation marks (\"). If you want to include a backslash character itself, you need two backslashes or use the @ verbatim string: "\\Tasks" or @"\Tasks".

Read the MSDN documentation/C# Specification which discusses the characters that are escaped using the backslash character and the use of the verbatim string literal.

Generally speaking, most C# .NET developers tend to favour using the @ verbatim strings when building file/folder paths since it saves them from having to write double backslashes all the time and they can directly copy/paste the path, so I would suggest that you get in the habit of doing the same.

 

 

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

Доброго времени суток! Коллеги, помогите пожалуйста с переводом запроса 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.

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

Всем доброго времени суток!

Столкнулся с такой проблемой, валятся ошибки при использовании ATF.Repository объектной модели и выгрузке данных в список:
 

[Schema("Account")]
    public class Account : BaseModel
    {       
        
        [SchemaProperty("Name")]
        public string Name { get; set; }        
        
        [DetailProperty("Account")]
        public virtual List<AccountWorkingTime> WorkingTimes { get; set; }
    }

[Schema("AbWorkingTimeStation")]
    public class AccountWorkingTime : BaseModel
    {
        [SchemaProperty("Account")]
        public Guid AccountId { get; set; }
        
        [LookupProperty("DayOfWeek")]
        public virtual DayOfWeek DayOfWeek { get; set; }
        
        [SchemaProperty("From")]
        public DateTime From { get; set; }
        
        [SchemaProperty("To")]
        public DateTime To { get; set; }

    }

namespace PlatformIntegration.Files.cs
{
    [DefaultBinding(typeof(IAccountAdapter))]
    public class AccountAdapter : IAccountAdapter
    {
        public UserConnection UserConnection { get; set; }

        public AccountAdapter(UserConnection userConnection)
        {
            UserConnection = userConnection;
        }
        private IRepository _repository;

        private IRepository Repository
        {
            get => _repository ??= new Repository
                {UserConnection = UserConnection, UseAdminRight = false};
            set => _repository = value;
        }

        public Models.Account GetAccountById(Guid id)
        {
            var account = Repository.GetItem<Models.Account>(id);
            return account;
        }        
    }
}

При отработке метода GetAccountById - вылазят ошибки https://prnt.sc/uh1zso

Terrasoft.Web.Common.ServiceModel.ErrorHandler HandleError - Error getting value from 'WorkingTimes' on 'Castle.Proxies.AccountProxy'.
Newtonsoft.Json.JsonSerializationException: Error getting value from 'WorkingTimes' on 'Castle.Proxies.AccountProxy'. ---> System.Reflection.TargetInvocationException: Адресат вызова создал исключение. ---> System.InvalidCastException: Объект должен реализовывать интерфейс IConvertible.
   в System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   в ATF.Repository.Repository.FillPropertyValue[T](T model, PropertyInfo propertyInfo, Object value)
   в ATF.Repository.Repository.FillPropertyValues[T](T model, IDictionary`2 values)
   в ATF.Repository.Repository.CreateItem[T](IDictionary`2 values)
   в ATF.Repository.Repository.LoadModelByValues[T](IDictionary`2 values)
   в ATF.Repository.Repository.<>c__DisplayClass64_0`1.<GetItems>b__0(IDictionary`2 recordValues)
   в System.Collections.Generic.List`1.ForEach(Action`1 action)
   в ATF.Repository.Repository.GetItems[T](String filterPropertyName, Guid filterValue)
   --- Конец трассировки внутреннего стека исключений ---
   в System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   в System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   в System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   в System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   в ATF.Repository.Repository.FillDetailValue[T](T model, ModelItem detail)
   в ATF.Repository.Builder.InstanceProxyHelper`1.FillProperty(IInvocation invocation, PropertyInfo property)
   в ATF.Repository.Builder.InstanceProxyHelper`1.InternalGet(IInvocation invocation, PropertyInfo property)
   в ATF.Repository.Builder.InstanceProxyHelper`1.Intercept(IInvocation invocation)
   в Castle.DynamicProxy.AbstractInvocation.Proceed()
   в Castle.Proxies.AccountProxy.get_WorkingTimes()
   в GetWorkingTimes(Object )
   в Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)
   --- Конец трассировки внутреннего стека исключений ---
   в Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)
   в Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)
   в Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   в Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
   в Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
   в Newtonsoft.Json.JsonConvert.SerializeObjectInternal(Object value, Type type, JsonSerializer jsonSerializer)
   в Newtonsoft.Json.JsonConvert.SerializeObject(Object value)
   в AutobookingPlatformIntegration.AccountIntegrationService.GetAccountById(Guid id)
   в SyncInvokeGetAccountById(Object , Object[] , Object[] )
   в System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
   в System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
   в System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
   в System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
   в System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
 

Кто нибудь сталкивался с таким поведением?

 

 

Нравится

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

Нашел в чем проблема. Не может десерелизовать в модель колонку с типом Время - https://prnt.sc/uhpw7o в DateTime. Кто работал с данным репозиторием знает решение данной проблемы?

Алексей, не вижу никаких упоминаний о ATF.Repository, кроме этой темы. Речь о тех ATF, которые сделали «.NET Core connector»? Там указан адрес на GitHub для связи с разработчиками. Возможно, они подскажут по этому механизму.

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

да, эти, писал и на почту, правда по другому вопросу, по текущему на гитхабе- пока ответа не получал

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

Задача: округлять дробную часть десятичного числа вверх.

Нашёл статью с методом на Microsoft https://docs.microsoft.com/en-us/dotnet/api/system.midpointrounding?vie… 

 

В БП пробую применять формулу Decimal.Round(([#Исходное дробное число#]), 1, MidpointRounding.AwayFromZero) - ругается, что "Допущена ошибка в формуле: Параметр "MidpointRounding" не найден.]."

При этом, если не использовать MidpointRounding, а просто указывать количество знаков после запятой Decimal.Round(([#Исходное дробное число#]), 1) - то формулу принимает и пересчёт ведёт, но по правилам округления, а не в бОльшую сторону, как мне нужно.

 

Может быть кто-то сталкивался с такой же задачей? Как решали?

Нравится

1 комментарий
Лучший ответ

Сергей, в отличие от старого движка процессов, в котором можно было указать в элементе-формуле или условии произвольный фрагмент C#-кода, в нынешнем, интерпретируемом, работа с формулами может не поддерживать все особенности функций от Microsoft.

 

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

decimal positiveValue = Get<decimal>("ProcessSchemaParameterPositiveValue");
decimal result = Math.Round(positiveValue, 1, MidpointRounding.ToEven);
Set<decimal>("ProcessSchemaParameterResult", result);
return true;

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

Сергей, в отличие от старого движка процессов, в котором можно было указать в элементе-формуле или условии произвольный фрагмент C#-кода, в нынешнем, интерпретируемом, работа с формулами может не поддерживать все особенности функций от Microsoft.

 

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

decimal positiveValue = Get<decimal>("ProcessSchemaParameterPositiveValue");
decimal result = Math.Round(positiveValue, 1, MidpointRounding.ToEven);
Set<decimal>("ProcessSchemaParameterResult", result);
return true;

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

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

Добрый день! При формировании такой структуры получаю NotSupportedException(внутри None):

 

{
    "QueryType": 1,
    "IsForceUpdate": false,
    "IsUpsert": false,
    "Filters": {
        "RootSchemaName": null,
        "FilterType": 0,
        "ComparisonType": 0,
        "LogicalOperation": 0,
        "IsNull": true,
        "IsEnabled": true,
        "IsNot": false,
        "SubFilters": null,
        "Items": {
            "primaryColumnFilter": {
                "FilterType": 1,
                "ComparisonType": 3,
                "LogicalOperation": 0,
                "IsNull": true,
                "IsEnabled": true,
                "IsNot": false,
                "SubFilters": null,
                "Items": null,
                "LeftExpression": {
                    "ExpressionType": 1,
                    "ColumnPath": null,
                    "Parameter": null,
                    "FunctionType": 1,
                    "MacrosType": 34,
                    "FunctionArgument": null,
                    "DatePartType": 0,
                    "AggregationType": 0,
                    "AggregationEvalType": 0,
                    "SubFilters": null
                },
                "RightExpression": {
                    "ExpressionType": 2,
                    "ColumnPath": null,
                    "Parameter": {
                        "DataValueType": 0,
                        "Value": "310ef086-1e11-4290-9c4e-90e78df4d69a",
                        "ArrayValue": null,
                        "ShouldSkipConvertion": false
                    },
                    "FunctionType": 0,
                    "MacrosType": 0,
                    "FunctionArgument": null,
                    "DatePartType": 0,
                    "AggregationType": 0,
                    "AggregationEvalType": 0,
                    "SubFilters": null
                },
                "RightExpressions": null,
                "RightLessExpression": null,
                "RightGreaterExpression": null,
                "TrimDateTimeParameterToDate": false,
                "Key": null,
                "IsAggregative": false,
                "LeftExpressionCaption": null,
                "ReferenceSchemaName": null
            }
        },
        "LeftExpression": null,
        "RightExpression": {
            "ExpressionType": 2,
            "ColumnPath": null,
            "Parameter": {
                "DataValueType": 0,
                "Value": "310ef086-1e11-4290-9c4e-90e78df4d69a",
                "ArrayValue": null,
                "ShouldSkipConvertion": false
            },
            "FunctionType": 0,
            "MacrosType": 0,
            "FunctionArgument": null,
            "DatePartType": 0,
            "AggregationType": 0,
            "AggregationEvalType": 0,
            "SubFilters": null
        },
        "RightExpressions": null,
        "RightLessExpression": null,
        "RightGreaterExpression": null,
        "TrimDateTimeParameterToDate": false,
        "Key": null,
        "IsAggregative": false,
        "LeftExpressionCaption": null,
        "ReferenceSchemaName": null
    },
    "QueryId": null,
    "QueryKind": 0,
    "ColumnValues": {
        "Items": {
            "UsrName": {
                "ExpressionType": 2,
                "ColumnPath": null,
                "Parameter": {
                    "DataValueType": 1,
                    "Value": "name96ae3de9-f90f-46a9-8b57-afeebedd6499",
                    "ArrayValue": null,
                    "ShouldSkipConvertion": false
                },
                "FunctionType": 0,
                "MacrosType": 0,
                "FunctionArgument": null,
                "DatePartType": 0,
                "AggregationType": 0,
                "AggregationEvalType": 0,
                "SubFilters": null
            },
            "UsrSalesFunnelStage": {
                "ExpressionType": 2,
                "ColumnPath": null,
                "Parameter": {
                    "DataValueType": 10,
                    "Value": "d136a6533-ee2b-4b4b-9366-ffe375568691",
                    "ArrayValue": null,
                    "ShouldSkipConvertion": false
                },
                "FunctionType": 0,
                "MacrosType": 0,
                "FunctionArgument": null,
                "DatePartType": 0,
                "AggregationType": 0,
                "AggregationEvalType": 0,
                "SubFilters": null
            },
            "UsrPartnerType": {
                "ExpressionType": 2,
                "ColumnPath": null,
                "Parameter": {
                    "DataValueType": 10,
                    "Value": "4397d6d7-0b95-43e6-9261-d01df863724f",
                    "ArrayValue": null,
                    "ShouldSkipConvertion": false
                },
                "FunctionType": 0,
                "MacrosType": 0,
                "FunctionArgument": null,
                "DatePartType": 0,
                "AggregationType": 0,
                "AggregationEvalType": 0,
                "SubFilters": null
            },
            "Id": {
                "ExpressionType": 2,
                "ColumnPath": null,
                "Parameter": {
                    "DataValueType": 0,
                    "Value": "310ef086-1e11-4290-9c4e-90e78df4d69a",
                    "ArrayValue": null,
                    "ShouldSkipConvertion": false
                },
                "FunctionType": 0,
                "MacrosType": 0,
                "FunctionArgument": null,
                "DatePartType": 0,
                "AggregationType": 0,
                "AggregationEvalType": 0,
                "SubFilters": null
            }
        }
    },
    "RootSchemaName": "UsrPartnersTest",
    "IncludeProcessExecutionData": true
}

все происходит в облаке

Нравится

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

Евгений, а что это за запрос был? Его формировали программно в коде или сгенерировался при работе с клиентской ESQ?

Смущает пустой RootSchemaName сверху, дважды переданный RightExpression с Guid (и третий раз он же как колонка). Я для пробы поменял значение в какой-то карточке, сохранил, у меня запрос к сервису совсем не такой вышел.

 

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

это BaseQuery сериализованный 

Terrasoft.Nui.ServiceModel.DataContract.BaseQuery, я заполнил структуру так (т к в документации нет примера):
var query = new UpdateQuery
            {
                IncludeProcessExecutionData = true,
                RootSchemaName = schemaName,
                ColumnValues = new ColumnValues
                {
                    Items = new Dictionary<string, ColumnExpression>()
                }
            };
 
 query.Filters = new Filters
            {
                RightExpression = new BaseExpression
                {
                    ExpressionType = EntitySchemaQueryExpressionType.Parameter,
                    Parameter = new Terrasoft.Nui.ServiceModel.DataContract.Parameter
                    {
                        DataValueType = DataValueType.Guid,
                        Value = id
                    }
                },
                Items = new Dictionary<string, Filter>
                {
                    {
                        "primaryColumnFilter", new Filter()
                        {
                            FilterType = FilterType.CompareFilter,
                            ComparisonType = FilterComparisonType.Equal,
                            IsEnabled = true,
                            LeftExpression = new BaseExpression
                            {
                                FunctionType = FunctionType.Macros,
                                ExpressionType = EntitySchemaQueryExpressionType.Function,
                                MacrosType = (EntitySchemaQueryMacrosType) 34,
                            },
                            RightExpression = new ColumnExpression
                            {
                                ExpressionType = EntitySchemaQueryExpressionType.Parameter,
                                Parameter = new Terrasoft.Nui.ServiceModel.DataContract.Parameter
                                {
                                    DataValueType = DataValueType.Guid,
                                    Value = id
                                }
                            }
                        }
                    }
                }
            };
 
            foreach (var parameterPair in operation.Parameters)
            {
                var columnExpression = new ColumnExpression
                {
                    ExpressionType = EntitySchemaQueryExpressionType.Parameter,
                    Parameter = new Terrasoft.Nui.ServiceModel.DataContract.Parameter
                    {
                        Value = parameterPair.Value.Value,
                        DataValueType = parameterPair.Value.Type,
                    }
                };
 
                query.ColumnValues.Items.Add(parameterPair.Value.Name, columnExpression);
            }

 

 

 

 

 

 

 

Всё равно не совсем понятно, почему сделали именно так.

Вы делаете внешний софт на C#, работающий с сервисами системы?

Документация по запросам обновления и фильтрам есть в академии.

Если же делаете внутри скриптов БП, то можно просто использовать класс Update.

Посмотреть структуру правильного запроса можно, проделав в интерфейсе аналогичное и записав, что ушло на сервер.

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

дело в том что я ориентировался как раз на запросы внутри самой crm. да, я реализую интеграцию с другими сервисами. Документация есть, но именно в обновлении примеров нет. И мне все-таки каким-то образом нужно понять что именно не так с запросом

 

В самой системе при обновлении записи получается совсем не такой запрос, как у Вас. Например, меняю индекс в адресе контакта:

{
   "rootSchemaName":"ContactAddress",
   "operationType":2,
   "includeProcessExecutionData":true,
   "filters":{
      "items":{
         "primaryColumnFilter":{
            "filterType":1,
            "comparisonType":3,
            "isEnabled":true,
            "trimDateTimeParameterToDate":false,
            "leftExpression":{
               "expressionType":1,
               "functionType":1,
               "macrosType":34
            },
            "rightExpression":{
               "expressionType":2,
               "parameter":{
                  "dataValueType":0,
                  "value":"9ce6c7ce-5ae4-df11-971b-001d60e938c6"
               }
            }
         }
      },
      "logicalOperation":0,
      "isEnabled":true,
      "filterType":6
   },
   "columnValues":{
      "items":{
         "Zip":{
            "expressionType":2,
            "parameter":{
               "dataValueType":1,
               "value":"105122"
            }
         }
      }
   },
   "isForceUpdate":false
}

 

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

остальные поля просто выходят в результате стерилизации BaseQuery от Terrasoft. Если его нужно использовать как-то иначе - дайте знать. Не хочется делать свой класс, учитывая что в библиотеке уже есть готовый

Горянин Евгений Юрьевич пишет:
остальные поля просто выходят в результате стерилизации BaseQuery от Terrasoft.

Но Вы же сами написали, что заполняете так. Зачем там два раза  RightExpression и подобное?

 

Может, лучше интеграцию по OData, как тут:

ИЗМЕНЕНИЕ СУЩЕСТВУЮЩЕГО ОБЪЕКТА

public static void UpdateCreatioEntityByOdatetWcfExample()
{
    // Создание контекста приложения Creatio.
    var context = new Creatio(serverUri);
    // Определение метода, который добавляет аутентификационные cookie при создании нового запроса.
    context.SendingRequest += new EventHandler<SendingRequestEventArgs>(OnSendingRequestCookie);
    // Из коллекции контактов выбирается тот, по которому будет изменяться информация.
    var updateContact = context.ContactCollection.Where(c => c.Name.Contains("Test")).First();
    // Изменение свойств выбранного контакта.
    updateContact.Notes = "New updated description for this contact.";
    updateContact.Phone = "123456789";
    // Сохранение изменений в модели данных сервиса.
    context.UpdateObject(updateContact);
    // Сохранение изменений данных в Creatio одним запросом.
    var responces = context.SaveChanges(SaveChangesOptions.Batch);
}

 

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

ну переделывать общий процесс под OData теперь уже нет возможности. с Select и Insert проблем не возникло, нужен какой-то пример на c# с использованием Update

На C# с запросами к данным работают либо через OData (во внешнем софте) либо внутри конфигурации системы через классы EntitySchemaQuery или Select/Insert/Update/Delete.

 

В Вашем случае это какой-то ещё один вариант. Если разобрались с Select и Insert, наверное и Update можно, чтобы в итоге к сервису уходил JSON, аналогичный отправляемому из браузера.

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

При отправке запроса к удалённому серверу 
Получаю ошибку:
 The request was aborted: Could not create SSL/TLS secure channel.

Нравится

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

Добрый день, Игорь.

Обратите внимание сюда.

Мотков Илья,

Спасибо, но это не помогло.
У меня есть подозрение, что ошибка происходит на этапе обращения из клиентской части к web-сервису  bpmonline по ссылке
Мой кейс:
Есть кнопка "прослушать"  в р. Звонки. При отправке запроса при клике на кнопку нельзя передать данные для аутентификации.
Поэтому ссылка для кнопки формируется к web-сервису bpmonline, который в свою очередь отправляет авторизованный запрос к удалённому серверу на получение потока.
CallStack ошибки не отображает вызов метода, который отправляет запрос к удалённому серверу, значит делаю вывод, что ошибка происходит на этапе вызова web-сервиса bpmonline.
Как обойти данную, ошибку ума не приложу.

 

Не видя, кто именно выдал ошибку, сложно сказать наверняка. Если сервер 7.Х, то более подробно будет в логах, если пришла от сервера телефонии, это сообщение будет видно при мониторинге HTTP-траффика от него.

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

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

Подскажите как можно из Бизнес процесса обратится к C# методу?

Нравится

2 комментария
Лучший ответ

Добрый день! Здесь -  http://prntscr.com/qr8kpl подключаем нам нужное пространство имен, затем объявляем экземпляр класса и вызываем метод - http://prntscr.com/qr8lqh 

Добрый день! Здесь -  http://prntscr.com/qr8kpl подключаем нам нужное пространство имен, затем объявляем экземпляр класса и вызываем метод - http://prntscr.com/qr8lqh 

Благодарю

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

Подскажите как можно в C# сделать Serialize в json объект класса

public class ImportCreatioServiceCaseColumns
{
	[JsonPropertyName("idNumber")]
	public string IdNumber { get; set; }
	[JsonPropertyName("typeCase1Name")]
	public string TypeCase0Name { get; set; }
}
public class ImportCreatioProcessCaseColumnsOut
{
	[JsonPropertyName("schemaName")]
	public string BusinessProcessName { get; set; }
	[JsonPropertyName("parameterValues")]
	public ImportCreatioServiceCaseColumns ImportCreatioServiceCaseColumns { get; set; }

}

и привести его к виду 

{
	"schemaName":"KtImportCaseTransferTableInBPMTest",
	"parameterValues":
	[
		{"name":"idNumber","value":"80001019"},
		{"name":"typeCase1Name","value":"Алматы"}
	]
}

?

Это нужно что бы передать body в микровервис для запуска бизнес-процесса с параметрами POST методом.

Нравится

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

Можно подключитье  Json.NET он уже включен в коробке. Подробнее об использовании смотрите https://www.newtonsoft.com/json

 

Как то так

 

sing System;
using Newtonsoft.Json;
 
namespace JsonPrettyPrint
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Product product = new Product
                {
                    Name = "Apple",
                    Expiry = new DateTime(2008, 12, 28),
                    Price = 3.99M,
                    Sizes = new[] { "Small", "Medium", "Large" }
                };
 
            string json = JsonConvert.SerializeObject(product, Formatting.Indented);
            Console.WriteLine(json);
 
            Product deserializedProduct = JsonConvert.DeserializeObject<Product>(json);
        }
    }
 
    internal class Product
    {
        public String[] Sizes { get; set; }
        public decimal Price { get; set; }
        public DateTime Expiry { get; set; }
        public string Name { get; set; }
    }
}

 

Не работает так как нужен именно такой формат, уже пробовал как Вы советуете 

Григорий Чех пишет:
{"name":"idNumber","value":"80001019"},

Похожий формат обсуждают тут.

 

Зверев Александр пишет:

Похожий формат обсуждают тут.

А Вы пробовали вызывать бизнес-процесс из другого приложения через post вызов передавая параметры через тело запроса? 

Александр, см. тут.

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

Всем доброго времени суток! 

Столкнулся со следующей проблемой, у нас в системе были кастомные Excel отчеты, выгружались посредствам библиотеки ClosedXml, и все работало, но с версии 7.14 перестало работать. Высыпаются ошибки в зависимостях:

Terrasoft.Web.Common.ServiceModel.ErrorHandler ProvideFault - Метод не найден: "System.IO.Packaging.PackageProperties DocumentFormat.OpenXml.Packaging.OpenXmlPackage.get_PackageProperties()".
System.MissingMethodException: Метод не найден: "System.IO.Packaging.PackageProperties DocumentFormat.OpenXml.Packaging.OpenXmlPackage.get_PackageProperties()

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

Кто работал с библиотекой ClosedXml в bpm'online, может знает какую версию использовать?

Текущая версия crm 7.14.4 

заранее благодарен.

Нравится

4 комментария
Лучший ответ

Столкнулся, к сожалению. пришлось все переписывать... В ClosedXML используются библиотеки DocumentFormat.OpenXml, в версии 7.14 видимо обновили версию библиотеки/зависимых библиотек и все. Мучался часа 3 с зависимостями, потом плюнул и переписал на OpenXml генерацию xls

Столкнулся, к сожалению. пришлось все переписывать... В ClosedXML используются библиотеки DocumentFormat.OpenXml, в версии 7.14 видимо обновили версию библиотеки/зависимых библиотек и все. Мучался часа 3 с зависимостями, потом плюнул и переписал на OpenXml генерацию xls

А что говорит по этому вопросу служба поддержки? Что они рекомендуют?

Алла Савельева,

Здравствуйте! Пока ничего. Анализирует предоставленный мною лог.

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

Поделитесь потом здесь ответом, очень интересует данная тема. Спасибо)

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