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

Нужна консультация.

У нас возникла необходимость обрабатывать большие коллекции Entity(изменять значение поля и обновлять) при этом что бы был задействован событийный слой.

Решили данным способом:

var bc = new BlockingCollection<Entity>();
// Наполнение коллекции
.....
Parallel.ForEach(bc, new ParallelOptions {
   MaxDegreeOfParallelism = Environment.ProcessorCount
}, entity => entity.UpdateInDB(false));

Вопрос в следующем будем ли мы ловить локи при использовании UserConnection entity, не создавая нового?
Подобные случаи с локами были на версии 7.8.


 

Нравится

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

Мне нужен фильтр в C# коде
Что-то вроде:

var activity = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "Activity"); //Активность
 
activity.Filters.Add(activity.CreateFilterWithParameters(FilterComparisonType.Equal, "Type",  "id типа")); // тип активности - email
activity.Filters.Add(activity.CreateFilterWithParameters(FilterComparisonType.Contain , "Recepient",  "my_email@gmail.com")); // кому-мне
 
activity.Filters.Add(activity.CreateFilterWithParameters(FilterComparisonType.Contain , "Sender",  "my_dad_email@gmail.com")); // от отца
activity.Filters.Add(activity.CreateFilterWithParameters(FilterComparisonType.Contain , "Sender",  "my_mum_email@gmail.com")); // от матери
activity.Filters.Add(activity.CreateFilterWithParameters(FilterComparisonType.Contain , "Sender",  "my_sister_email@gmail.com")); // от сестры
activity.Filters.Add(activity.CreateFilterWithParameters(FilterComparisonType.Contain , "Sender",  "my_brother_email@gmail.com")); // от брата

нужен такой фильтр:
тип активности-email && кому-мне && (от отца || от матери || от сестры || от брата)

Как добавить логические операторы чтобы получить такой фильтр?
Или может быть надо по другому?

Нравится

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

 Что то типо такого?

activity.Filters.Add(activity.CreateFilterWithParameters(FilterComparisonType.Contain , "Sender",  new string[] { "my_dad_email@gmail.com", "my_mum_email@gmail.com", "my_sister_email@gmail.com", "my_brother_email@gmail.com"}));

Колногоров Роман Андреевич,

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

Условие типа "Contain" не может содержать более одного выражения в правой части
обойтись без Contain не получиться

Попробуйте через createColumnInFilterWithParameters

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

Как вызывать из JS я знаю, но тут понадобилось вызвать из C#

Нравится

1 комментарий
var property = "PropertyValue";				
ProcessSchema schema = SystemUserConnection.ProcessSchemaManager.GetInstanceByName("ProcessName");
				bool canUseFlowEngine = ProcessSchemaManager.GetCanUseFlowEngine(UserConnection, schema);
				if(canUseFlowEngine) {
					var flowEngine = new FlowEngine(UserConnection);
					var param = new Dictionary<string, string>();
					param["Property"] = property;
					flowEngine.RunProcess(schema, param);
				} else {
					Process process = schema.CreateProcess(UserConnection);
					process.SetPropertyValue("Property", property);
					process.Execute(UserConnection);
				}

В принципе проверку на canUseFlowEngine можно смело убрать, сейчас все процессы запускаются через FlowEngine.

Показать все комментарии
using Terrasoft.Common;
new LocalizableString(UserConnection.Workspace.ResourceStorage, "ИмяКласса",
					"LocalizableStrings.TestMessageBody.Value").ToString();

 

Нравится

Поделиться

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

Добрый день, всем. Очень долго выполняются запросы связанные с UpdateQuery, SelectQuery, InsertQuery. Кто-нибудь сталкивался с этим? Какие пути использовали, для нахождения проблемы?

Нравится

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

Для анализа запросов есть профайлер в mssql. Запускаете профайлере, делаете запрос из клиентской части. Смотрите какой sql для select получается в профайлере.

Еще может быть, что у вас тормозит обмен по websocket. Надо посмотреть в консоль разработчика в браузере, нет ли там ошибки с подключение к websocket.

И еще creatio требовательна к ресурсам, если вам кажется что все работает медленно, то стоит проанализировать производительность ваших серверов.

Для анализа запросов есть профайлер в mssql. Запускаете профайлере, делаете запрос из клиентской части. Смотрите какой sql для select получается в профайлере.

Еще может быть, что у вас тормозит обмен по websocket. Надо посмотреть в консоль разработчика в браузере, нет ли там ошибки с подключение к websocket.

И еще creatio требовательна к ресурсам, если вам кажется что все работает медленно, то стоит проанализировать производительность ваших серверов.

В profiler смотрел, запросы выполняются за доли миллисекунд.
Websocket работает отлично.
Запросы выполняются долго в момент переключения состояния Обращения, вот что заметил. Пока не отлаживал сам процесс перехода состояний, но может уже кто-то сталкивался с этим.

Саид Иманмагомедов,

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

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

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

Как создать задачу на визирование в коде?

Нравится

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

EntitySchema invoiceVisaSchema = UserConnection.EntitySchemaManager.GetInstanceByName("InvoiceVisa");
Entity invoiceVisa = invoiceVisaSchema.CreateEntity(UserConnection);
invoiceVisa.SetDefColumnValues();
invoiceVisa.SetColumnValue("Objective", "Требуется утверждение");
invoiceVisa.SetColumnValue("VisaOwnerId", new Guid("7F3B869F-34F3-4F20-AB4D-7480A5FDF647"));
invoiceVisa.SetColumnValue("StatusId", new Guid("3462594D-77A7-4B0A-874A-6D8B54B293BC"));
invoiceVisa.SetColumnValue("InvoiceId", new Guid("3C2B6D9F-4C1E-4364-99F2-53956562B606"));
invoiceVisa.Save();

 

аналог элемент процесса

EntitySchema invoiceVisaSchema = UserConnection.EntitySchemaManager.GetInstanceByName("InvoiceVisa");
Entity invoiceVisa = invoiceVisaSchema.CreateEntity(UserConnection);
invoiceVisa.SetDefColumnValues();
invoiceVisa.SetColumnValue("Objective", "Требуется утверждение");
invoiceVisa.SetColumnValue("VisaOwnerId", new Guid("7F3B869F-34F3-4F20-AB4D-7480A5FDF647"));
invoiceVisa.SetColumnValue("StatusId", new Guid("3462594D-77A7-4B0A-874A-6D8B54B293BC"));
invoiceVisa.SetColumnValue("InvoiceId", new Guid("3C2B6D9F-4C1E-4364-99F2-53956562B606"));
invoiceVisa.Save();

 

аналог элемент процесса

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

Добрый день, возникла проблема, что я не могу взять больше 20 тыс одним запросом, поэтому было решено ограничить , брав только первую запись из выборки , каким образом это можно сделать. (это не бизнес процесс)

 

Нравится

6 комментариев
var userConnection = Get<UserConnection>("UserConnection");
var esq = new EntitySchemaQuery(userConnection.EntitySchemaManager, <SchemaName>);
esq.AddAllSchemaColumns();
esq.Filters.Add(esq.CreateFilterWithParameters(FilterComparisonType.Equal, <FieldName>, fieldValue));
var enitites = esq.GetEntityCollection(userConnection);
ver entity = enitites.FirtsOrDefault();

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

Дамиан, так делать неправильно, в момент GetEntityCollection всё равно будут получены все записи, соответствующие условиям.

Правильнее будет перед этим дописать:

esq.RowCount = 1;

Аналогично и с колонками, оставить только нужные.

Дмитрий, а почему такие крайности, от 20000 к 1? Что именно Вы получаете и что потом с этими данными делаете? Может, подобрать оптимальный размер порции для обработки за раз?

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

Александр, спасибо за уточнение. Нашёл еще один подход.

public Entity GetEntity(UserConnection userConnection)
{
    var entitySchema = userConnection.EntitySchemaManager.GetInstanceByName(name);
    var esq = new EntitySchemaQuery(entitySchema);
    esq.AddAllSchemaColumns();
    return esq.GetEntity(userConnection, primaryColumnValue);
}

 

Тут всё зависит, сколько реально записей отфильтруется по такому условию. Если всегда 0 или 1, то можно и первым, и вторым Вашим способом. А если есть риск получить 100500 результатов, то лучше перестраховаться, ограничив количество в запросе.

Зверев Александр,
у нас логи по 1с пишутся в системе, куда отправили , что отправили , также получаем данные из 1с, из-за этого логов за один проход чуть больше 100 получается каждые пол часа
а первую запись из выборки мне надо для нумерации этих логов

Соответственно он не сможет дальше писать ничего , если при записи лога взял пулом 20 тыс записей разом

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

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

Подскажите пожалуйста как можно настроить тестовые данные, для того что бы протестировать 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 и как строить пути к колонкам, а в данной статье показано как получить данные из запроса.

Здравствуйте! В данной статье описано как работать с классом 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.

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