Коллеги, приветствую.

Есть определенный интерес поизучать классы Select, Insert, Update, EntitySchemaQuery и подробнее
разобраться, как с ними работать.

Чтобы это было проще и быстрее мне бы хотелось иметь возможность работать с ними из MS Visual Studio.

Например, запрос из статьи Использование EntitySchemaQuery для построения запросов к базе данных:

// Создание экземпляра запроса, добавление в запрос колонок и источника данных.
Select selectQuery = new Select(UserConnection)
                    .Column("Id")
                    .Column("Name")
                    .From("Contact");
// Выполнение запроса к базе данных и получение результирующего набора данных.
using (DBExecutor dbExecutor = UserConnection.EnsureDBConnection())
{
    using (IDataReader reader = selectQuery.ExecuteReader(dbExecutor))
    {
        while (reader.Read())
        {
            // Обработка результатов запроса.
        }
    }
}

Собственно, вопрос в конфигурировании класса UserConnection, как его использовать "вне платформы", не в режиме отладки?

Например, в методе Main:

static void Main(string[] args)
{
}

В элементе "Задание- сценарий" я могу получить его таким образом:

var userConnection = Get("UserConnection");

В Web- сервисе WCF:

var userConnection = (UserConnection)HttpContext.Current.Session["UserConnection"];

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

Нравится

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

Здравствуйте.
Если сайт у вас развернуть on-site, то есть, поднят на своем IIS сервере:
Тогда у вас есть возможность написать свой, к примеру, веб-сервис, или даже скрипт-сценарий, и пользуясь статьей по отладке,
http://academy.terrasoft.ru/documents/docs/technic/SDK/7.6.0/ServerCode…
ставить точки останова, и изучать поведение серверного ESQ.
Здесь главное, что бы код был частью системы, поэтому его и нужно писать как часть системы (веб-сервис, бизнес-процесс, и.т.д.), а не сторонние dll,exe,итд.
С автономной программы этого сделать не получится.

Если же сайт on-demand, то есть, развернут как http://имя-сайта.bpmonline.com/
То такой возможности у Вас нет, и со стороннего процесса (программы), Вы никак не обратитесь к ядру системы.
Из сторонних программ написанных Вами в Visual Studio, Вы можете разве что обратится к уже написанным веб-сервисам в рамках структуры сайта, либо же по протоколу OData,
http://academy.terrasoft.ua/documents/docs/technic/SDK/7.4.1/WorkWithBp… что, конечно же, совсем не запросы ESQ.

Александр, спасибо большое за ответ!

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

Добрый день!

Кто-то баловался с переключением clientUnits useFileContent="true" / "false" ?

Появилась потребность новых разделов, решил "наклепать" мастером, так как вроде приятнее и проще там делать. Но вот незадача - обратное переключение не показывает "мастеровые" метаданные. Удалял все js-файлы, и делал "обновить клиентские модули из базы данных", но ощущение что есть две разных ветки клиентских модулей, так как переключение между режимами даёт разные картинки. Что же не так делаю?

Нравится

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

Добрый день.
Для первичного создания нового раздела проблем не будет даже при useFileContent="true". После создания раздела нужно обновить клиентские модули из БД.

Перед отключением выгрузки клиентских модулей на диск, обязательно выполнить фиксацию клиентских модулей в БД.
После повторного включения необходимо выполнить действие "Обновить клиентские модули из БД".

Обратите внимание, что мастер может затереть subscriber для деталей, если код указан в теле функции, а не ссылка на метод.

"Пащенко Александр Сергеевич" написал:Для первичного создания нового раздела проблем не будет даже при useFileContent="true". После создания раздела нужно обновить клиентские модули из БД.

Как-то появляются проблемы: кусками данные есть.

"Пащенко Александр Сергеевич" написал:После повторного включения необходимо выполнить действие "Обновить клиентские модули из БД".

Делаю, но проблема не лечится.

"Пащенко Александр Сергеевич" написал:Обратите внимание, что мастер может затереть subscriber для деталей, если код указан в теле функции, а не ссылка на метод.

Не очень понятно. Задача тупо создать новый раздел с новыми деталями (ну и подкорректировать, при необходимости) мастером...

Здравствуйте.
Попробуйте выполнить следующее: включить usefilecontent и обновить клиентские модули из бд. После этого выполнить очистку кеша.

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

Доброе утро коллеги.
Подскажите какой скрипт необходимо написать, чтобы преобразовать тип данных "Уникальный идентификатор" в "Int" который выводиться в поле Целое число ?

Если есть шаблоны буду благодарен за ссылки.
Спасибо.

Нравится

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

А как вы себе представляете отображение в виде целого числа выражения '{2B885FFE-8226-4AAD-9468-64A0C50DA01B}' ?

Понял. Тогда как преобразование в String ?

с#
Variable.ToString()

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

Коллеги, приветствую.

Есть некоторый запрос, который возвращает дату платежа и дату последней активности по платежу:

SELECT
        ContactId AS debtorId,
        t1.CreatedOn AS activityDate,
        t2.CreatedOn AS paymentDate
FROM Activity AS t1 INNER JOIN UsrPayments AS t2
        ON t1.ContactId = t2.UsrDebtorId
WHERE t1.CreatedOn = (
        SELECT max(CreatedOn) FROM Activity
        WHERE t1.ContactId = t2.UsrDebtorId
);

И есть некоторый код C#, где с помощью подзапроса я хочу определить дату последней активности по платежу, аналогично тому, как я это делаю выше на native SQL:

var selectNewPayments = (Select)new Select(userConnection)
        .Column("t1", "ContactId")
        .Column("t1", "CreatedOn")
        .Column("t2", "CreatedOn")
        .From("Activity").As("t1")
        .Join(JoinType.Inner, "UsrPayments").As("t2")
        .On("t1", "ContactId").IsEqual("t2", "UsrDebtorId")
        .Where("... здесь подзапрос и обращение к функции max() ...")
        as Select;

Как этот подзапрос написать?

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

Нравится

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

Здравствуйте!
Все функции описаны по ссылке.

Пример:

SELECT 
C.Name,
(SELECT COUNT(*) FROM Activity A WHERE A.ContactId = C.Id) As ActivityCount
FROM Contact C

Перевод в С#:

var subSelect = new Select(userConnection)
                .Column(Func.Count(Column.Asterisk()))
.From("Activity").As("A")
.Where("C", "Id").IsEqual("A", "ContactId").As("ActivityCount")
var select = new Select(userConnection)
                .Column("C", "Name")
                .Column(subSelect)
.From("Contact").As("C")

Супер! Алексей, спасибо большое.

А можно то же самое, только не Select'ом а с помощью ESQ?

Здравствуйте, Олег!

Примеры доступны по ссылке:
https://www.terrasoft.ru/bpmonlinesdk/UsingEntitySchemaQuery.html

"Шамшин_Олег" написал:А можно то же самое, только не Select'ом а с помощью ESQ?

1. Делаете один esq запрос на содержимое подзапроса, выбираете из него, список Id, или чего вам нужно, в оригинальном посте подзапрос выбирал CreatedOn. Формируете массив этих CreatedOn.

2. В колбеке после возврата результата подзапроса, формируете новый esq запрос, с фильтрацией нужной колонки, в оригинальном посте CreatedOn на вхождение в массив ранее выбранных CreatedOn.

Т.к. фильтрация createColumnInFilterWithParameters спокойно проверит вхождение колонки и в массив.
Пример оторванный от контекста esq, рассматривает только создания фильтра, но такой фильтр подставленный в esq будет работать и в esq:
http://www.community.terrasoft.ru/forum/topic/11497#comment-50859

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

Коллеги, приветствую.

В бизнес- процессе эмулируется некоторая активность, "отправка СМС".

Я хочу в заголовок записать ряд параметров, например, ФИО, сумму задолженности и пр.

Что- то вроде этого:

"Уважаемый ФИО, у Вас имеется долг в размере ДОЛГ"

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

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

Нравится

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

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

У элемента "Задача" есть параметр Recommendation. Вам необходимо передать значение в него.
Для передачи есть две базовые возможности (+элемент "Задание-сценарий", но это сложный способ):
1) Найти в структуре процесса элемент "Задача" и в элементе "Задача" в параметр Recommendation установить значение по умолчанию
2) Использовать элемент "Формула"

В двух вариантах параметр необходимо заполнить следующим значением:
"Уважаемый "+[#ФИО#]+", у Вас имеется долг в размере "+[#ДОЛГ#]

(отдельный параметры необходимо разделять знаком "+", текст необходимо писать в двойных кавычках, перенос на новую строку осуществляется последовательностью символов \\n

Алексей, спасибо большое! Сейчас попробую.

Супер, работает. Спасибо!

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

Коллеги, приветствую.

Есть несколько бизнес- процессов, каждый из которых использует общие ресурсы (таблицы). Например, бизнес- процесс A инициируется событием- добавлением записи в таблицу "Задолженности", выполняет чтение задолженностей по всем договорам должника и меняет в добавленной записи значение в колонке "Общая сумма задолженности". Бизнес- процесс Б инициируется тем же событием и реализует логику погашения задолженности, оперируя теми же таблицами, что и бизнес- процесс А. Как будут выполняться процессы? Какой из них начнется первым, если начальное событие одно и то же?

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

Нравится

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

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

Плохая реализация - могут быть падения одного из процессов, т.к. таблица будет заблокирована другим процессом. Лучше делать все внутри одного процесса. Вы можете изменить в одном из процессов стартовый сигнал на обычный начальный элемент и добавить параметр с типом "Уникальный идентификатор", а во втором процессе вызывать этот процесс элементом "Подпроцесс", передавая в параметр подпроцесса Id записи.

Здравствуйте, Алексей! Спасибо большое за ответ!

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

Коллеги, приветствую.

Есть некоторый код C# в действии "Задание- сценарий", читающий из базы данных определенную информацию и, если таковая есть - устанавливает параметр процесса, скажем, isNewPayments.

Далее по процессу у меня есть "исключающее или" и два варианта потоков соответственно.

var userConnection = Get("UserConnection");
Set("isNewPayments", -1);

var selectNewPayments = (Select)new Select(userConnection)
   .Column("t1", "ContactId")
   .Column("t1", "CreatedOn")
   .Column("t2", "CreatedOn")
   .From("Activity").As("t1")
   .Join(JoinType.Inner, "UsrPayments").As("t2")
   .On("t1", "ContactId").IsEqual("t2", "UsrDebtorId")
   .Where("t1", "CreatedOn").IsLess("t2", "CreatedOn")
   .OrderByAsc("t1", "id") as Select;

using (DBExecutor dbExecutor = userConnection.EnsureDBConnection())
{
    using (IDataReader reader = selectNewPayments.ExecuteReader(dbExecutor))
    {
        if(reader.Read()) {
                Set("isNewPayments", 1);
        } else {
                Set("isNewPayments", -1);
        }
    }
}

return true;

Это работает.

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

Если для метода Get я могу указать тип,

var isNewPayments = Get("isNewPayments");

- то как указать тип для метода Set, если аргумент- коллекция объектов?

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

Нравится

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

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

Уточните, пожалуйста, Вашу задачу.

Вы хотите в параметр процесса записывать коллекцию объектов, или параметр процесса хранит коллекцию и Вы хотите ее получить в элементе "Задание-сценарий"?

Алексей, спасибо за ответ! Вообще же, было бы интересно узнать, как быть и в том, и в другом случае.
Если я оперирую объектами, например, то могу читать параметры бизнес- процесса и устанавливать таким образом:

// Чтение параметра бизнес- процесса
var paramOne = Get<Decimal>("paramOne"); // Тип данных в дизайнере "Дробное число (0,01)"
 
...
paramOne = decimal.Parse(reader["UsrColumnWithData"].ToString());
...
 
// Запись в параметр бизнес- процесса, тип данных не указываю - работает
Set("paramOne", paramOne);

В случае с коллекцией объектов, как использовать Get и Set?

Добрый день!
В новом движке процессов работать можно только с параметрами процесса, либо напрямую с параметрами элементов, на которые настроен маппинг.
Т.е. если есть результат коллекции, с которым необходимо работать в Задание-сценарий подойдет такой пример:
1. Создать параметр процесса типа Строка - TestParam.
2. В значение параметра указать [#Read data 1.First item of resulting collection#].GetTypedColumnValue("Name")
3. В элементе Задание-сценарий работать с параметром.
var contactFullName = Get("TestParam");

Или в свойствах элемента Задание-сценарий убрать птичку "Для интерпретируемого процесса" и писать код как для старого движка.

Здравствуйте, Олег! Спасибо большое за ответ!

Олег, а как быть если ситуация обратная? Сценарий сформировал коллекцию обьектов и её нужно передать в параметр БП?

"Горовецкий Вячеслав Илларионович" написал:

Олег, а как быть если ситуация обратная? Сценарий сформировал коллекцию обьектов и её нужно передать в параметр БП?

Приведите, пожалуйста, пример, где элемент "Задание-сценарий" формирует коллекцию, которая дальше используется по процессу.

Например, я пишу вебсервис, как у вас описано на академии (кстати тот пример не рабочий в 7.7). Этот сервис вызывает бизнес процесс, состоящий из одного элемента типа скрипт, который по заданным параметрам работает с ESQ и формирует, допустим некий список контрагентов (это коллекция неких объектов). Этот список нужно передать в исходящий параметр для выгрузки в качестве результата работы вебсервиса.

А теперь вопрос. Какой должен быть тип исходящего параметра у процесса (Entity или массив Entity) и как в него передать список объектов, полученных в скрипте?

Пример для интерпретируемого процесса:
Важно! В процессе в Usings необходимо подключить:
Terrasoft.Common.Json

var myUserConnection = context.UserConnection;
var esq = new EntitySchemaQuery(myUserConnection.EntitySchemaManager, "Account");
var nameColumn = esq.AddColumn("Name");
var primaryContactColumn = esq.AddColumn("PrimaryContact.Name");
var gorovetskiyContactId = new Guid("CEDA7503-8EAC-4581-B88F-DB537A27EB2C");
var filter = esq.CreateFilterWithParameters(FilterComparisonType.Equal, "PrimaryContact", gorovetskiyContactId);
esq.Filters.Add(filter);
var entityCollection = esq.GetEntityCollection(myUserConnection);
if (entityCollection.Count == 0) {
Set("AccountList", string.Empty);
return true;
}
var accounts = new List ();
foreach(var entity in entityCollection) {
var account = new {
Name = entity.GetTypedColumnValue(nameColumn.Name),
PrimaryContact = entity.GetTypedColumnValue(primaryContactColumn.Name)
};
accounts.Add(account);
}
string serialized = Json.Serialize(accounts);
Set("AccountList", serialized);
// пример для компилируемого процесса: AccountList = serialized
// параметр процесса AccountList - тип неограниченная строка – параметр процесса
//Json.Deserialize>(source) – пример, как выполнить обратное действие
return true;

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

Коллеги, приветствую.

Есть некоторый запрос, который возвращает информацию по должнику и последней активности, проявленной в отношении него:

SELECT
        TOP 1  
        ContactId as id,
        AC.CreatedOn as activityDate,
        UP.CreatedOn as paymentDate

FROM
        Activity as AC INNER JOIN UsrPayments as UP
                ON AC.ContactId = UP.UsrDebtorId
WHERE
        UP.CreatedOn  > AC.CreatedOn

ORDER BY AC.id ASC;

И есть некоторый код на C#, где с помощью класса Select проделывается то же, но считываются записи по всем активностям:

var selectNewPayments = (Select)new Select(userConnection)
                .Column("t1", "ContactId")
                .Column("t1", "CreatedOn")
                .Column("t2", "CreatedOn")
                .From("Activity").As("t1")
                .Join(JoinType.Inner, "UsrPayments").As("t2")
                .On("t1", "ContactId").IsEqual("t2", "UsrDebtorId")
                .Where("t1", "CreatedOn")
                .IsLess("t2", "CreatedOn") as Select;

Как прочитать только первую запись?

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

Нравится

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

Нашел, собственно -

var selectNewPayments = (Select)new Select(userConnection)
   .Top(1)
   .Column("t1", "ContactId") 
   .Column("t1", "CreatedOn")
   .Column("t2", "CreatedOn")
   .From("Activity").As("t1")
   .Join(JoinType.Inner, "UsrPayments").As("t2")
   .On("t1", "ContactId").IsEqual("t2", "UsrDebtorId")
   .Where("t1", "CreatedOn").IsLess("t2", "CreatedOn").OrderByAsc("t1", "id") as Select;

Такой запрос возможен???

select count(ID)

   from [dbo].[Case] AS TI

WHERE DATEPART(HOUR, DATEADD(hh, 6, TI.[UsrDueDate])) >=9  and DATEPART(HOUR, DATEADD(hh, 6, TI.[UsrDueDate])) <12

and FORMAT(DATEADD(hh, 6, TI.[UsrDueDate]), N'yyyy.MM.dd') = FORMAT(cast(GETDATE() +1 as date), N'yyyy.MM.dd')

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

Добрый день!

Необходимо в кампании реализовать цель "Провести 3 встречи" или "Получить проектов на определенную сумму".
Это осуществимо в BPM'Online Marketing? каким образом?

Нравится

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

Добрый день, Оксана!

В версии bpm’online marketing 7.7 есть возможность создавать кампании только со следующими элементами: Email-рассылка, лендинг, мероприятие, аудитория, создание лида.

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

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

Спасибо за ответ.

Интересует вопрос именно о цели кампании:
Возможность изменения строчки "я хочу___%Участников___"

Оксана, спасибо за уточнение!

Значение указанной Вами строки подставляется в зависимости от локализации. Ее можно изменить, предварительно заменив карточку CampaignPageV2.

Однако, хочу обратить Ваше внимание, что верстка рассчитана на размер базовых слов([я хочу], [%Участников]), это нужно учесть при внесении изменений.

Кроме того, рассчет показателей [Достигли цели], [Осталось] осуществляется на основании данных, введенных в соответствующее поле строки "я хочу___%Участников___".

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

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

Добрый день.
Столкнулся с проблемой в процессе настройки механизма уведомления по документам.
DocumentNotificationProvider в системе уже был, его добавил в NotificationProvider.
Уведомления создаются так же, как и в активностях. Запись в Reminding создается корректно.
Уведомление появляется, но не понятно почему в виде "от 05.04.2016" без гиперссылки и иконки.
Буду благодарен за идеи!
Версия 7.7.0.2223

Нравится

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

Добрый день!

Приведите примеры своего процесса, или схемы (прикрепите выгруженный файл), чтобы можно было проанализовать данный вопрос детальнее.

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

SynchronizeReminding.IsSubjectDelete = Entity.IsInDeleting;
SynchronizeReminding.Active = !Entity.IsInDeleting;
SynchronizeReminding.SubjectPrimaryColumnValue = Entity.PrimaryColumnValue;
SynchronizeReminding.Contact = Entity.GetTypedColumnValue<Guid>("OwnerId");
SynchronizeReminding.Source = new Guid("a76d08e1-2e2d-e011-ac0a-00155d043205");
SynchronizeReminding.RemindTime = Entity.GetTypedColumnValue<DateTime>("SxRemindingDate");
SynchronizeReminding.SysEntitySchema = Entity.Schema.UId;
SynchronizeReminding.Description = "Договор №" + Entity.GetTypedColumnValue<string>("Number");
SynchronizeReminding.NotificationType = RemindingConsts.NotificationTypeRemindingId;
SynchronizeReminding.TypeCaption = "Договор";

Добрый день!
Немогли бы Вы прикрепить все замещенные схемы?

Был только замещен объект документ, в нем в процессе прописана вся логика создания напоминаний.
Прикрепил скрин процесса. Содержание скрипта приведено выше.

Добрый день!

Посмотрите реализацию схемы SystemNotificationsSchema, метод getNotificationItemConfig().
На этом примере можно реализовать отображение необходимых данных как гиперссылок.

Я так и не понял, почему напоминания по активностям, которые создаются таким же образом отображаются корректно? Так же в предыдущих версиях bpm проблем с напоминаниями не было и не нужно было что-то реализовывать сверх добавления записи в Reminding и провайдера. И не понятно что и где нужно теперь реализовывать...

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

В 770 были изменены отображения уведомлений. Теперь на вкладке "Уведомления" можно делать ссылки только на счета и активности. Другие уведомления считаются системными (на самом деле зависит от значения в поле NotificationType).
Об этом Вы можете прочитать здесь.

Получается, что для других разделов теперь можно создавать только системные уведомления и обойти это никак не получится?

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

Обойти возможно все) Формально, можно создать уведомление на активность, при открытии которой будет открываться счет. Для этого Вы можете воспользоваться функционалом бизнес процессов. В бизнес процессе есть элемент "Страница редактирования". Этот элемент создает активность, но при открытии активности, открывается страница другой сущности. В настройках элемента "Открыть страницу редактирования" в поле "Напомнить за" Вам необходимо указать значение, отличное от 0. В результате, уведомление будет сформировано.

Спасибо, будем пробовать!

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