Зачастую приложение разработанное на BPMOnline, как и последующие его доработки требуется предоставлять в виде "all inclusive", т.е. всё что нужно, в т.ч. и настройки и бэкраунд-данные должны быть в Ваших пакетах, и единственное что остается сделать клиенту или его специалистам - это установить их. Но в части механизма переноса данных в самой архитектуре приложения есть проблемные моменты, в основном часто встречающиеся юзкейсы:

1) Перенос/инсталляция элементов организационной структуры, или изменений в ней через пакет.
проблематика: Через "Данные" не переносятся, подключить их в пакет у Вас конечно получится с кучей связей, но при установке вас ожидает фиаско, в первую очередь потому, что требуется четкое соблюдение порядка добавления записей, в таблице SysAdminUnits есть внутренние связи FK между колонками Id и ParentId (значение одной колонки ссылается на значение из другой колонки этой же таблицы). Этими значениями определяется иерархия, по этому Вам необходимо добавлять записи в соответствии с их положением в дереве: от корня в глубь.
совет: организовывайте вашу структуру в мастере в том числе проставьте галочки на "Есть руководители" (т.к. создается отельный орг.юнит), после чего в любом удобном инструменте просмотра таблиц БД, в таблице SysAdminUnits отсортируйте записи по колонке "CreatedOn" в порядке возрастания, и в таком виде экспортируйте INSERT инструкции для каждой записи отдельным блоком.
PS: так же зачастую требуется перенос значений из таблиц SysAdminUnitsInRole (пользователи включенные в орг.юнит), и SysFuncRoleInOrgRole (связи орг.юнитов друг с другом),
а перед инсталяцией орг.юнитов пользователей - сначала инсталируйте контакты с которыми они будут связаны.

2) Перенос/инсталляция настроек рабочих мест, или изменений в них через пакет.
проблематика: По той причине что организационную структуру Вы через данные не переносите, настройка рабочих мест просто не даст Вам создать данные так, как вы не включаете в виде данных необходимые значения для орг.юнитов.
PS: Сами рабочие места, и даже разделы вы можете перенести через данные,
но если вам нужны данные о пользователях группах пользователей в раб.местах - тут только SQL-скрипт. Так что лучше уж тогда все переносить в скрипте.

3) Перенос/инсталляция настройки колонок в реестрах, деталях, окнах выбора и т.д.
проблематика: Через "Данные" не переносятся, т.к. содержат бинарные данные в 2-х колонках (ObjectData, ObjectDifference) таблицы SysProfileData по какой-то причине не включаются в пакет вместе с данными, и аналогично предыдущему пункту вы можете создать такие "Данные", но при инсталляции получите записи с пустыми вышеупомянутыми колонками.
совет: Опять же настраиваем "ручками в системе" потом отлавливаем новые записи в любом SQL-view, дампим записи (их будет 2-3 на каждый элемент настройки колонок) в блоках INSERT, но в данном случае не забудьте, что вам при инсталляции надо будет проверить существуют ли в таблице записи с такими же соотношениями колонок "Key" - "ContactId" и удалить их (не обновлять) если они есть после чего вставлять Ваши записи.

Вообщем у Вас может получиться объемистая часть данных которые надо включать в пакеты в виде SQL-скрипта. И идеальный подход для этого конечно использование подхода "Вставить, а если существует - обновить".
Так вот TSQL не предлагает каких либо "сахарных" инструкций aka MySQL UPSERT или PostgreSQL ON DUPLIKATE KEY
В TSQL ближайший аналог это монстроузный MERGE который можно использовать для реализации вышеупомянутого подхода, ну конечно можно еще c использование IF EXISTS писать еще более "монструозные простыни", и даже делать SELECT->FOR-IF-UPDATE/INSERT но это уж простите меня - совсем "нубство".
Первый взгляд на MERGE вас конечно немного испугает и заставит пропотеть, особенно учитывая тот факт что вам не обойтись без многократного описания колонок и их соотношений, а в большинстве таблиц с которыми Вам его надо будет применять - более 10-ти колонок. :) а Вам понадобится их перечисление в 4-х местах в разном виде.
Но на помощь нам приходят современные средства разработки !
Итак... вот вам пошаговый рецепт составления такого скрипта на примере составления MERGE для переноса/обновления из таблицы SysAdminUnits в среде Jetbrains DataGrip (если вы или Ваши друзья коллеги студенты IT-смежной специальности, Вы без проблем получите ключ на год на весь пантеон из продуктов, WebStrom просто незаменим для JavaScript, особенно в свете того что с 7.10 версии наконец-то можно работать с пакетами в файловом режиме)
PS: наверняка в SQL Managment Studio можно обвеситься плагинами и получить аналогичную функциональность (я сейчас про некоторые хоткеи и мультикурсорность, которые и есть суть - все сильно упрощают), если это так - прошу знатоков отписаться в комментариях что для этого потребуется, или же подтвердить что там так не выйдет.
Итак поехали:
Копируем шаблон конструкции

DROP TABLE IF EXISTS #Temp;
CREATE TABLE #Temp
(

);

MERGE TargetTable AS dst
USING #Temp AS src
ON (dst.Id=src.Id)
WHEN MATCHED THEN
    UPDATE SET

WHEN NOT MATCHED BY TARGET THEN
    INSERT
    (

    )
    VALUES (

    );
GO

ДАЛЬНЕЙШИЕ ИЗОБРАЖЕНИЯ ЭТО GIF-АНИМАЦИЯ, CLICKайте и ПРОСМАТРИВАЙТЕ
Открываем необходимую таблицу в структуре и переходим к ее определению (вкладка DDL)
поиск в боковой схеме - простой набор символов с клавиатуры при выделении любой таблицы
открытие таблицы - F4


и копируем определение колонок в определение колонок временной таблицы шаблона, даем временной таблице осмысленное имя,

и вот тут начнется "магия" мультиселекта это IDE
Alt+j (установка мультикурсорности на обнаруженных паттернах выделенного фрагмента)
Нам необходимо избавиться в обявлении колонок от значений "по умолчанию" (не знаю почему, но с этим иногда бывают проблемы, в контексте нашей задачи, проще избавиться, чтобы наверняка).
А так же удалем FK определения они нам само собой тоже не нужны

При помощи мощи мультиселекта и хоткеев паттерного выделения (выделить слово, добить/убрать из выделения символ) "творим магию"

обратите внимание на то, что лишние запятые изначально оставляются чтобы все строки соответствовали паттерну, а потом удаляются, остается установить имя целевой таблицы.
и вот мы получили вот такой вот скрипт
DROP TABLE IF EXISTS #TempSysAdminUnits;
CREATE TABLE #TempSysAdminUnits
(
  Id UNIQUEIDENTIFIER PRIMARY KEY NOT NULL,
  CreatedOn DATETIME2,
  CreatedById UNIQUEIDENTIFIER,
  ModifiedOn DATETIME2,
  ModifiedById UNIQUEIDENTIFIER,
  Name NVARCHAR(250) NOT NULL,
  Description NVARCHAR(250) NOT NULL,
  ParentRoleId UNIQUEIDENTIFIER,
  ContactId UNIQUEIDENTIFIER,
  TimeZoneId NVARCHAR(250) NOT NULL,
  UserPassword NVARCHAR(250) NOT NULL,
  SysAdminUnitTypeValue INT NOT NULL,
  AccountId UNIQUEIDENTIFIER,
  Active BIT NOT NULL,
  LoggedIn BIT NOT NULL,
  SynchronizeWithLDAP BIT NOT NULL,
  LDAPEntry NVARCHAR(250) NOT NULL,
  LDAPEntryId NVARCHAR(250) NOT NULL,
  LDAPEntryDN NVARCHAR(500) NOT NULL,
  IsDirectoryEntry BIT NOT NULL,
  ProcessListeners INT NOT NULL,
  SysCultureId UNIQUEIDENTIFIER,
  LoginAttemptCount INT NOT NULL,
  SourceControlLogin NVARCHAR(250) NOT NULL,
  SourceControlPassword NVARCHAR(250) NOT NULL,
  PasswordExpireDate DATETIME2,
  HomePageId UNIQUEIDENTIFIER,
  ConnectionType INT NOT NULL,
  UnblockTime DATETIME2,
  ForceChangePassword BIT NOT NULL,
  LDAPElementId UNIQUEIDENTIFIER,
  DateTimeFormatId UNIQUEIDENTIFIER,
);

MERGE SysAdminUnits AS dst
USING #TempSysAdminUnits AS src
ON (dst.Id=src.Id)
WHEN MATCHED THEN
    UPDATE SET
      dst.CreatedOn=src.CreatedOn,
      dst.CreatedById=src.CreatedById,
      dst.ModifiedOn=src.ModifiedOn,
      dst.ModifiedById=src.ModifiedById,
      dst.Name=src.Name,
      dst.Description=src.Description,
      dst.ParentRoleId=src.ParentRoleId,
      dst.ContactId=src.ContactId,
      dst.TimeZoneId=src.TimeZoneId,
      dst.UserPassword=src.UserPassword,
      dst.SysAdminUnitTypeValue=src.SysAdminUnitTypeValue,
      dst.AccountId=src.AccountId,
      dst.Active=src.Active,
      dst.LoggedIn=src.LoggedIn,
      dst.SynchronizeWithLDAP=src.SynchronizeWithLDAP,
      dst.LDAPEntry=src.LDAPEntry,
      dst.LDAPEntryId=src.LDAPEntryId,
      dst.LDAPEntryDN=src.LDAPEntryDN,
      dst.IsDirectoryEntry=src.IsDirectoryEntry,
      dst.ProcessListeners=src.ProcessListeners,
      dst.SysCultureId=src.SysCultureId,
      dst.LoginAttemptCount=src.LoginAttemptCount,
      dst.SourceControlLogin=src.SourceControlLogin,
      dst.SourceControlPassword=src.SourceControlPassword,
      dst.PasswordExpireDate=src.PasswordExpireDate,
      dst.HomePageId=src.HomePageId,
      dst.ConnectionType=src.ConnectionType,
      dst.UnblockTime=src.UnblockTime,
      dst.ForceChangePassword=src.ForceChangePassword,
      dst.LDAPElementId=src.LDAPElementId,
      dst.DateTimeFormatId=src.DateTimeFormatId
WHEN NOT MATCHED BY TARGET THEN
    INSERT
    (
      Id,
      CreatedOn,
      CreatedById,
      ModifiedOn,
      ModifiedById,
      Name,
      Description,
      ParentRoleId,
      ContactId,
      TimeZoneId,
      UserPassword,
      SysAdminUnitTypeValue,
      AccountId,
      Active,
      LoggedIn,
      SynchronizeWithLDAP,
      LDAPEntry,
      LDAPEntryId,
      LDAPEntryDN,
      IsDirectoryEntry,
      ProcessListeners,
      SysCultureId,
      LoginAttemptCount,
      SourceControlLogin,
      SourceControlPassword,
      PasswordExpireDate,
      HomePageId,
      ConnectionType,
      UnblockTime,
      ForceChangePassword,
      LDAPElementId,
      DateTimeFormatId
    )
    VALUES (
      src.Id,
      src.CreatedOn,
      src.CreatedById,
      src.ModifiedOn,
      src.ModifiedById,
      src.Name,
      src.Description,
      src.ParentRoleId,
      src.ContactId,
      src.TimeZoneId,
      src.UserPassword,
      src.SysAdminUnitTypeValue,
      src.AccountId,
      src.Active,
      src.LoggedIn,
      src.SynchronizeWithLDAP,
      src.LDAPEntry,
      src.LDAPEntryId,
      src.LDAPEntryDN,
      src.IsDirectoryEntry,
      src.ProcessListeners,
      src.SysCultureId,
      src.LoginAttemptCount,
      src.SourceControlLogin,
      src.SourceControlPassword,
      src.PasswordExpireDate,
      src.HomePageId,
      src.ConnectionType,
      src.UnblockTime,
      src.ForceChangePassword,
      src.LDAPElementId,
      src.DateTimeFormatId
    );
GO

потратив на его составление менее 5-ти минут :)
Ну а далее в этот скрипт перед операцией MERGE перенесите INSERT конструкциями, то что требуется изменив назначение на временную таблицу

Вуаля... итого 5-7 минут и готово.
Другими способами и копипастой, такой скриптик писать с таким огромным разношерстным объявлением - минут 20-30 :)
Так что юзайте возможности современных средств разработки коллеги.

Нравится

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

мы на 79 переносили оргструктуру, пользователей и даже права на объекты через данные
там есть два момента:
1) надо сбросить, а после установки пакета вернуть, триггер TRSysAdminUnitRoot (без триггера не было проблем с установкой SysAdminUnit - я так понимаю механизм установки следит за порядком SAME REFERENCE записей)
2) (не уверен надо ли это вообще)) следить за порядком установки (он алфавитный) - контакты перед пользователями, роли перед пользователями и вхождениями ролей в роли и пользователей в роли (SysUserInRole, т.к. SysAdminUnitsInRole - заполняется в процессе актуализации оргструктуры см сленд пункт)
3) после установки пакета выполнить tsp_ActualizeAdminUnitInRole, просто чтобы не забыть сделать это вручную
4) осторожнее с корневыми ролями и Supervisor'ом

и вроде с SysProfileData тоже не было проблем

"Андросов Дмитрий" написал:3) после установки пакета выполнить tsp_ActualizeAdminUnitInRole, просто чтобы не забыть сделать это вручную

Да, это важное и полезное дополнение :)
Спасибо.

"Андросов Дмитрий" написал:(не уверен надо ли это вообще)) следить за порядком установки (он алфавитный)

ну вот это прям сомнительное утверждение :)
Ну если я конечно понимаю о чем идет речь.
Так как у потомка в колонке ParentId идет FK на Id этой-же таблицы, т.е. порядок просто ОБЯЗАН быть соблюден, иначе лови ошибки FK инсерта строк на уровне таблицы SysAdminUnit, при установке через данные именно в этом и проблема:
Мы профилировали запросы и там INSERT идет через перечисление VALUES а не каждая строка отдельной инструкцией... (так что тут фактически повезет / не повезет как сортируются значения в перечислении мне не ведомо да и мы в любом случае не можем это контролировать)

"Севостьянов Илья Сергеевич" написал:да и мы в любом случае не можем это контролировать

мы можем контролировать порядок иначе:
создаем данные на корневые роли, называем "SysAdminUnit1Roles"
далее на роли второго уровня, называем "SysAdminUnit2Roles"
далее на третий, называем "SysAdminUnit3Roles" и т.д.
[странно, но мы переносили 5ти уровневую оргструктуру в одних данных, поэтому и сомневался - не разбирает ли установщик данных, что в рамках одних данных установить сначала?]
после этого на самих пользователей "SysAdminUnit999Users" (контакты пользователей установили ранее)
после этого на SysUserInRole для переноса вхождения пользователей в группы

я имел ввиду, что во время установки по алфавиту упорядочиваются не записи, а схемы данных

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

Добрый день, подскажите, пожалуйста, как можно реализовать sql запрос на удаление данных в элементе "Задание- сценарий" БП или же в схеме карточки:

DELETE FROM [dbo].[Lead] WHERE [Id] = 'c6deb935-c86e-44f6-9101-eec17473c1df'

В БП в сценарии таким способом не выходит подключить userConnection:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using Terrasoft.Common;
using Terrasoft.Core;
using Terrasoft.Core.DB;
using Terrasoft.Core.Entities;
var delete = new Delete(userConnection)
.From("Lead")
.Where("Id").IsEqual(Column.Parameter("{c6deb935-c86e-44f6-9101-eec17473c1df}"));
return true;

Нравится

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

Добрый день, Мария!

Вы можете получить экземпляр UserConnection следующим образом:

UserConnection UserConnection = Get("UserConnection");

Спасибо, теперь возникает ошибка:

The type arguments for method 'Terrasoft.Core.Process.ProcessModel.Get(string)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

Если убрать галочку с "Для интерпретируемого процесса", то процесс выполняется успешно, но лид не удаляется, хотя напрямую sql запросом удаление происходит, в чем может быть проблема?

"Maria H" написал:пасибо, теперь возникает ошибка:

Илья чуть-чуть ошибся, метод гет, это дженерик метод, ему нужно передавать тип, следовательно получение коннекшена будет выглядеть следующим образом:

var userConnection = Get<UserConnection>("UserConnection");
Показать все комментарии

Добрый день, коллеги!
Создаем в разделе новое обращение. В колонку Контрагент добавляем новую запись, которой нет в базе следующим образом: https://yadi.sk/d/3cVtO41M3G6nBG После заполнения необходимых полей при сохранении выдает следующую ошибку: https://yadi.sk/i/g-V0CAGN3GRYcs
Как это исправить?

Нравится

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

Добрый день, Елена!
Данная проблема известна. Мы ее исправили в версии 7.10 (в ближайшее время будет релиз).
Если исправление необходимо внести локально на Ваш сайт, пожалуйста, обратитесь в поддержку с указанием проблематики и адреса сайта.
Спасибо за понимание.

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

esq = Ext.create("Terrasoft.EntitySchemaQuery", {
                                                                rootSchemaName: "CurrencyRate"
                                                        });
                                                        esq.addColumn("Rate");
                                                        //var startDate = esq.addColumn('StartDate');
                                                        //startDate.orderDirection = Terrasoft.OrderDirection.DESC;
                                                       
                                                        var yesterday = new Date();
                                                        var tomorrow = new Date();
                                                        yesterday.setDate(tomorrow.getDate() - 1);
                                                        tomorrow.setDate(tomorrow.getDate() + 1);
                                                       
                                                        esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
                                                                        this.Terrasoft.ComparisonType.EQUAL, "Currency", this.get("LogCurrencyRow").value));
                                                        esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
                                                                        this.Terrasoft.ComparisonType.GREATER, "Startdate", yesterday));
                                                        esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
                                                                        this.Terrasoft.ComparisonType.LESS, "Startdate", tomorrow));

                                                        esq.getEntityCollection(function(response) {
                                                                if (response.success) {
                                                                        response.collection.each(function(item) {
                                                                                CurrencyRate = item.get("Rate");
                                                                        }, this);
                                                                }
                                                                else if (CurrencyRate === 0)
                                                                {

Не могу разобраться с датой. Без даты работает.
Что не так?
Помогите пож-та.

Нравится

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

"Юсупов Марат" написал:esq.addColumn('StartDate');

"Юсупов Марат" написал:this.Terrasoft.ComparisonType.GREATER, "Startdate", yesterday))

Так StartDate или Startdate? А вообще, хотелось бы увидеть скрин консоли с ошибкой)

Также обратите внимание, что в переменную yesterday и tomorrow попадёт текущее время:

yesterday
Sun Mar 19 2017 16:14:13 GMT+0300 (RTZ 2 (зима))
tomorrow
Tue Mar 21 2017 16:14:13 GMT+0300 (RTZ 2 (зима))

Для "чистоты" запроса можно его подправить:

yesterday = Terrasoft.startOfDay(yesterday)
Sun Mar 19 2017 00:00:00 GMT+0300 (RTZ 2 (зима))
tomorrow = Terrasoft.endOfDay(tomorrow)
Tue Mar 21 2017 23:59:59 GMT+0300 (RTZ 2 (зима))

Данила, спасибо.
Привыкнуть не могу что регистр важен.
Заработало, спасибо.

var LogCurrencyUpper = this.get("LogCurrencyRow"); //.value; toUpperCase()
 
							esq = Ext.create("Terrasoft.EntitySchemaQuery", {
								rootSchemaName: "CurrencyRate"
							});
							esq.addColumn("Rate");
							var yesterday = new Date();
							yesterday = Terrasoft.startOfDay(yesterday)
							var today = new Date();
							today = Terrasoft.endOfDay(today)
 
							esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
									this.Terrasoft.ComparisonType.EQUAL, "Currency", this.get("LogCurrencyRow").value));
							esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
									this.Terrasoft.ComparisonType.GREATER, "StartDate", yesterday));
							esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
									this.Terrasoft.ComparisonType.LESS, "StartDate", today));
 
							esq.getEntityCollection(function(response) {
								if (response.success) {
									response.collection.each(function(item) {
										CurrencyRate = item.get("Rate");
									}, this);
								}
								else if (CurrencyRate === 0)
								{
//код
								}

Спасибо еще раз. :smile:

Чтото перестало работать
ошибка в консоли

Error while sending request 
	response status: 500 (FormatException)
	request url: ../DataService/json/SyncReply/SelectQuery
	method: POST
	request data: {"rootSchemaName":"CurrencyRate","operationType":0,"filters":{"items":{"b5859fc2-36c6-4b78-a147-1a8f8cbff7cd":{"filterType":1,"comparisonType":3,"isEn...
var _tomorrow = new Date();
							_tomorrow.setDate(_tomorrow.getDate() + 1);
							var _yesterday = new Date();
							_yesterday.setDate(_yesterday.getDate() - 1);
 
							_tomorrow = Terrasoft.endOfDay(_tomorrow);
							_yesterday = Terrasoft.startOfDay(_yesterday);
 
 
							esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
									this.Terrasoft.ComparisonType.EQUAL, "Currency", LogCurrencyRow));
							esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
									this.Terrasoft.ComparisonType.GREATER, "StartDate", _yesterday));
							esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
									this.Terrasoft.ComparisonType.LESS, "StartDate", _tomorrow));
 
							esq.getEntityCollection(function(response) {
 
}
 
								else
								{
									}

Интересная вещь в хроме время нормальное показывает, а в файрфоксе по гринвичу.
Данный главное есть.

Id CreatedOn CreatedById ModifiedOn ModifiedById StartDate EndDate CurrencyId Rate ProcessListeners RateMantissa
906BD40D-2955-4E62-9F84-44B46CB6F5BF 2017-03-22 10:08:54.057 NULL 2017-03-22 10:08:54.057 NULL 2017-03-22 NULL C0057119-53E6-DF11-971B-001D60E938C6 62.2699 0

Еще нашел такое у responce

В "{0}" ожидалось шестнадцатеричное значение 0x.

Нашел свой косяк.

esq.filters.addItem(Terrasoft.createColumnFilterWithParameter(
                                                                        this.Terrasoft.ComparisonType.EQUAL, "Currency", LogCurrencyRow.value));
Показать все комментарии

Есть потребность простом запросе на проверку данных.
Найти примеров не смог и есть ли они вообще.

if(new Select(userConnection)
                                                .Column("StartDate")
                                                .From("CurrencyRate")
                                                .Where("StartDate").IsEqual(Column.Const(_date)).Execute() > 0)
{
  // код
}

Как я понимаю можно так?

Нравится

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

Если это серверная логика, то так:

if ((new Select(UserConnection).Column(Func.Count("Id")).From("ActivityCorrespondence").Where("ActivityId").IsEqual(Column.Parameter(Entity.ActivityId)) as Select).ExecuteScalar<int>() > 0) {
//...
}

Также учтите, что поле «StartDate» хранит дату-время, поэтому на равенство сравнивать нет смысла, нужно взять интервал двух дат начала и конца периода (то есть дня) и сравнивать при помощи «IsLessOrEqual» и «IsGreaterOrEqual».

Вышла ошибка как только переделал

UserConnection является тип но используется как переменная

if ((new Select(UserConnection)
.Column(Func.Count("Rate"))
.From("CurrencyRate")
.Where("StartDate").IsLessOrEqual(Column.Const(_today))
.And("StartDate").IsGreaterOrEqual(Column.Const(_yesterday))
.ExecuteScalar() > 0))
{
return "That date already exists!";
} else {

Напишите с маленькой буквы.

Нашел ошибку в коде
Но ошибка все равно выходит

Чтобы ошибка не выходила, её нужно исправить.

Мой косяк.
Спасибо, заработало.

DateTime _today = DateTime.Today;
				DateTime _yesterday = DateTime.Today.AddDays(-1);
				var userConnection = (UserConnection)HttpContext.Current.Session["UserConnection"];
 
				var entityRowCount = (new Select(userConnection)
						.Column(Func.Count("Rate"))
						.From("CurrencyRate")
						.Where("StartDate").IsLessOrEqual(Column.Const(_today))
							.And("StartDate").IsGreaterOrEqual(Column.Const(_yesterday))
						as Select).ExecuteScalar<int>();
				if ( entityRowCount > 0) 
				{
					return "That date already exists!";
				} else {

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

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

Коллеги, доброе утро!
В C# блоке бизнес-процесса выполняется следующий скрипт:

 Select caseDeadlineResponseSelect = new Select(userConnection).
         Column("Case", "id").As("CaseId").
         From("Case").
         Where("Case", "StatusId").IsEqual(Column.Parameter(caseStatusNew))
         .And("Case", "NrbSentDeadlineResponse").IsEqual(Column.Parameter("0"))
         .And(Func.DateDiff(DateDiffQueryFunctionInterval.Minute, Column.Const(dateNow), new QueryColumnExpression("RegisteredOn"))/
         Func.DateDiff(DateDiffQueryFunctionInterval.Minute, new QueryColumnExpression("ResponseDate"), new QueryColumnExpression("RegisteredOn"))).IsGreaterOrEqual(Column.Parameter(0.9))
         as Select;

Проблема в том, что в блоке WHERE в частности где идет идет деление дат, происходит округление в большую сторону, т.о как правило результат выражения
Func.DateDiff(DateDiffQueryFunctionInterval.Minute, Column.Const(dateNow), new QueryColumnExpression("RegisteredOn"))/
         Func.DateDiff(DateDiffQueryFunctionInterval.Minute, new QueryColumnExpression("ResponseDate"), new QueryColumnExpression("RegisteredOn")))
всегда равен больше единицы. В обычном SQL, я бы произвел конвертацию делимого и делителя:
CONVERT(decimal(10,2),DATEDIFF(MINUTE, GETDATE(), RegisteredOn))/
CONVERT(decimal(10,2),DATEDIFF(MINUTE, ResponseDate, RegisteredOn))

Но как произвести конвертацию в C# блоке я не понял. Я использовал функцию CAST, но не смог подобрать DBDatValueType.
Подскажите, как все таки произвести вычислениях хотя бы до десятых долей.

Нравится

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

В принципе, можно вписать произвольный SQL-код через Column.SqlText.
Примеры работы с ним можно найти в конфигурации. Вот тут тоже работают с датами:

var campaignPurchaseQtyCountSelect = new Select(UserConnection)
		.Column(Func.Count("Id"))
		.From("CampaignPurchaseQtyCount")
		.Where("CampaignId").IsEqual("Campaign", "Id")
		.And("CardId").IsEqual(Column.Parameter(cardId))
		.And(Column.SqlText("DATEDIFF(D, 0, [PurchaseDate])")).IsEqual(Column.SqlText("DATEDIFF(D, 0, @purchaseDate)"));
if (purchaseEntity.GetTypedColumnValue<Guid>("TypeId").Equals(Terrasoft.Configuration.PurchaseConsts.ReturnTypeUId)) {
	campaignPurchaseQtyCountSelect
		.And("IsRewarded").IsEqual(Column.Parameter(false));
}

BEHOLD!!!!

DBDataValueType valueType = userConnection.DataValueTypeManager.GetInstanceByUId(DataValueType.FloatDataValueTypeUId) as DBDataValueType;
 
DateDiffQueryFunction diff1 = Func.DateDiff(DateDiffQueryFunctionInterval.Day, Column.Const(DateTime.UtcNow), new QueryColumnExpression("CreatedOn")),
	diff2 = Func.DateDiff(DateDiffQueryFunctionInterval.Day, new QueryColumnExpression("TmResponseDate"), new QueryColumnExpression("CreatedOn"));
 
QueryColumnExpression exp1 = new QueryColumnExpression(diff1), exp2 = new QueryColumnExpression(diff2);
CastQueryFunction cast1 = Func.Cast(exp1, valueType), cast2 = Func.Cast(exp2, valueType);
 
 
QueryColumnExpression exp3 = new QueryColumnExpression(cast1), exp4 = new QueryColumnExpression(cast2);
QueryColumnExpression result = QueryColumnExpression.Divide(exp3, exp4);
 
Select decSelect = new Select(userConnection).Top(1)
	.Column(result)
	.From("TmNews")
as Select;
return decSelect.ExecuteScalar<float>();

В итоге выдаёт 0.6666667 на тестовом примере. Но эт жесть, конечно:smile:

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

Прошу помощи у коллективного разума, т.к. официальная поддержка отклонила этот вопрос по SLA, как касающийся разработки "новой функциональности", хотя это очевидная просьба о разъяснении логики работы встроенных механизмов.

На конфигурации "A" - разрабатывался пакет в его составе предусмотрено несколько SQL-скриптов.
Они были созданы с Типом установки "После сохранения пакета".
Пакет был успешно перенесен в другую конфигурацию ("B") через SVN, т.е. установлен там из репозитория в котором из конфигурации "A" он был зафиксирован.

После установки пакета в конфигурацию "B",
И выполнения пункта действий конфигуратора "Установить для требующих обновления" - скрипты были выполнены и с них снялся признак "Требует установки в БД".

А вот в искомой конфигурации "А" (где разрабатывался пакет и откуда он фиксировался в SVN) после "Установки этих скриптов" - выполнении действия конфигуратора "Установить выбранные элементы" - признак "Требует установки в БД" - не снимается,
Что приводит к их постоянному повторному выполнению, когда кто либо в конфигурации использует "Установить для требующих установки".
Можно ли, и если да то как снять этот признак принудительно ?

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

PS: 3 доступных значения "Тип установки",
не ясно чем они отличаются, когда и при каких условиях выполняются.
(в документации всего 2 упоминания на 97-й странице, ничего никак не разъясняющие)
Не очень понятно, что например подразумевается под типом установки "После сохранения пакета".
О каком "сохранении" идет речь ?
Т.е. они выполняются каждый раз когда пакет - что?
Фиксируется в репозитории или устанавливается из него, или при каждом обновлении пакета.

Нравится

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

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

Можно ли, и если да то как снять этот признак принудительно? - Да можно, вот простой скрипт:

update SysPackageSqlScript set NeedInstall = 0 where name = ''

Т.е. они выполняются каждый раз когда пакет - что? - когда пакет сохраняется в БД

Если будете переносить пакеты при помощи WorkspaceConsole, Вы сможете увидеть в какой момент времни происходит выполнение sql скриптов.

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

Добрый день,

Для начала короткая тру-стори. Как мы все знаем, иногда появляются ситуации, когда нужно сделать простенький sql запрос. Хорошо, когда система развернута on-site (management studio вам в помощь), однако у некоторых система в облаке. Товарищи из "Программные Технологии" в своё время запилили программку sql_executer (за что им ОГРОМНОЕ спасибо), но в ней обнаружился забавный баг: данные при нескольких select-ах наползали друг на друга + при переносе на новые версии (7.8, 7.9) ломался интерфейс. В новой же редакции они распространяют свой продукт через маркетплейс.

Недавно мне понадобился обновленный executor, запрос на него висит уже дня 2-3... Вся эта ситуация привела к написанию своего варианта реализации запросов к бд.

pic

Итак, плюсы:
1) Произвольные select-запросы, update, delete и т.п Вообще все, что угодно, ибо всё работает через CustomQuery
2) Работают tab и F5 (ура!)

Минусы:
1) Это ни в коем случае не супер-оттестированный продукт.
2) Так и не заработала маска :( Поэтому, если запрос выполняется очень долго, то узнать об этом можно по зависанию интерфейса (пример: select * from sysimage)

В итоге: решение годится для тех случаев, когда надо срочно что-то подсмотреть/выполнить, но неохота часто лезть в конфигурацию или ждать ответа с заказа на маркетплейсе.

Прикрепляю архив для установки пакета и архив со схемами (5 штук, для простого импорта).
После установки: Дизайнер системы -> пункт "Импорт и Интеграция" -> Запросы в Бд

Нравится

Поделиться

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

Данила, спасибо за feedback!
Маркетплейс удобен (в основном конечно в недалеком будущем:wink:) тем, что там всегда доступна актуальная протестированная Террасофтом рабочаяя версия продукта для любой версии платформы. Кроме того, сейчас у команды в работе задачи по выгрузке в csv, сохранению запросов в историю и прочее, и конечно мы будем поддерживать продукт в плане обновления версий платформы.

"запрос на него висит уже дня 2-3..." - надеюсь это не SQL запрос:lol::lol::lol:

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

По любым продуктам/проектам Программных Технологий ты всегда можешь писать мне напрямую - svistunov@samarasoft.ru, либо запрашивать продукты через наш сайт актуальную последнюю вресию. В феврале мы выпускаем еще 3 продукта, которые будем поддерживать и развивать + 3 продукта запланировано на март + 3 на апрель.

На основе обратной связи поставил себе в план:

  • Предоставить актуальные пакеты. Во вложении.
  • В понедельник сделаю пост на комьюнити с анонсом продуктов (чтобы не было потребности переизобретать велосипеды из-за моментов взаимодействия): PT SMS Connector, PT External File Storage, PT Virtual Cashbox, PT JIRA Connector, PT Process Scheduler, PT Questionnaire, PT Currency Rates, PT Pulse Notifications. Думаю, назначение большинства понятно из названия:smile:
  • В течение следующей недели обязаюсь ответным комментарием выложить публичный svn для наших бесплатных продуктов

Анонс по текущим и новым продуктам опубликовал.

Публичный SVN для продуктов - http://svn.ptsoft.ru/public/

Попробовал установить SQL Executor на стандартную демку sales team в облаке Terrasoft через стандартный модуль "Установка приложений".  Продукт не встал, лог могу выслать, если разработчику интересно.

Лев, высылай, можно на меня, я передам коллегам

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

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

При настройке системы иногда возникает потребность внесения ряда изменений на уровне базы данных.
Наш бесплатный модуль для bpm’online позволяет техническим специалистам осуществлять выборки из базы данных и выполнять SQL-команды наиболее удобным способом и без потери времени.
Особенно эта возможность актуальна для пользователей сайтов on-demand, когда доступ к базе данных ограничен.

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

SQL

Будем рады ответить на ваши вопросы!

С уважением,
Зайчиков Илья
Менеджер продуктов
ООО «Программные Технологии»
Центр разработки и внедрения Террасофт Поволжье
Тел. +7 (846) 266-55-69
Email: galanin@samarasoft.com
samarasoft.com

Нравится

Поделиться

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

Насколько понимаю, это развитие Вашей же утилиты под 5.Х?

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

Да, всё верно. Эта версия позволяет более удобно выполнять SQL запросы в интерфейсе 7.X, в новой версии появилась подсветка синтаксиса языка SQL, возможность настроить разграничение доступа к данному модулю, выполнять одновременно несколько select запросов (как это позволяет делать SQL Management Studio), выполнять сортировку полученных результатов и обрабатывать ошибки в случае некорректного написания SQL-команды.

С уважением,
Зайчиков Илья

Бесплатно, но "спасибо" оставлю :)

Сходил по ссылке, заявку оставил, да так мне и не дали чудо утилиту... :cry:

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

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

С уважением,
Зайчиков Илья

"Зайчиков Илья Алексеевич" написал:А утилиту мы конечно же предоставим!

Еще раз отправил заявку))

Александр,

Я уже вам отправил ссылку для скачивания в скайп.

С уважением,
Зайчиков Илья

"Зайчиков Илья Алексеевич" написал:Я уже вам отправил ссылку для скачивания в скайп.

Поймал, спасибо огромное

Александр,

Всегда рады помочь!

С уважением,
Зайчиков Илья

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

Доброго времени суток.
Как правильно написать команду SQL типа (Type), воспринимает ее как (Select, where, as и т.д.) в обычное поле в которое можно записывать. Поле Type имеется у таблицы в БД, оно системное, возможности переименовать ее нет.
Например:

SELECT DISTINCT
[Product].[Id] as [ProductID],
[Product].[Type] as [TypeID],

P.S.:Двойные и одинарные скобки не помогают.

Нравится

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