Добрый день!

После недавнего обновления Win10 (KB4056892), в Terrasoft 3.4.0.130 перестал отображаться пользователь в верхней части окна, отсутствуют напоминания и при переходе во вкладку Сделки появляется ошибка(та, что на скриншоте). Возможно кто-то сталкивался? Если обновление удалить все работает.

Изображение удалено.

Нравится

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

Этот сбой возникает на Windows 10 после прихода обновления KB4074588, которое ломает в Terrasoft пользовательские настройки. А этот раздел одну из них при открытии проверяет, как и механизм напоминаний.

Для восстановления нормальной работы нужно либо удалить из Windows это обновление KB4074588, либо запускать Terrasoft к компьютеров не под Windows 10. В руководстве администратора Terrasoft 3.4.0 указаны как поддерживаемые Windows XP, Windows Server 2003, Windows Vista, Windows Server 2008 и Windows 7.

Для быстрого перехода на другой компьютер достаточно просто целиком скопировать папку Terrasoft, а затем запустить в окне логина нажать лупу и так же настроить доступ в базу. Первый запуск TSClient.exe на новом месте нужно произвести под администратором Windows, нажав правую кнопку мыши на файле.

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

Большое спасибо

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

Собираюсь использовать службу DataService с клиентской части, так как совсем не разбираюсь в С#. Но в документации для чтения и добавления примеры для JS есть, а для удаления и обновления записей -
нет. Прошу помощи: буду очень признателен за пример удаления и обновления записи через DataService на из клиентской части)

Нравится

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

Для обновления ищите по конфигурации слова "Terrasoft.UpdateQuery"
примеров множество, вот из OpportunityManagementEndOfStagePreconfiguredPage:

var updateQuery = Ext.create("Terrasoft.UpdateQuery", {
	rootSchemaName: "Activity"
});
updateQuery.filters.addItem(this.Terrasoft.createColumnFilterWithParameter(
		Terrasoft.ComparisonType.EQUAL, "Id", activityId));
updateQuery.setParameterValue("Status",
		ConfigurationConstants.Activity.Status.Cancel,
		this.Terrasoft.DataValueType.LOOKUP);
updateQuery.execute(function() {
	this.loadActivities();
}, this);

Удаление по словам "Terrasoft.DeleteQuery", примеров так же очень много, вот из DocumentRelationshipDetailV2:

var deleteQuery = this.Ext.create("Terrasoft.DeleteQuery", {
	rootSchemaName: "DocumentRelationship"
});
var masterRecordId = this.get("MasterRecordId");
var filters = this.getDeleteRelationFilters(masterRecordId, selectedRows);
deleteQuery.filters.add("DocumentsFilter", filters);
deleteQuery.execute(function() {
	this.hideBodyMask();
	this.deselectRows();
	this.reloadGridData();
}, this);

"Максим Шевченко" написал:

Для обновления ищите по конфигурации слова "Terrasoft.UpdateQuery"

примеров множество, вот из OpportunityManagementEndOfStagePreconfiguredPage:

var updateQuery = Ext.create("Terrasoft.UpdateQuery", {

        rootSchemaName: "Activity"

});

updateQuery.filters.addItem(this.Terrasoft.createColumnFilterWithParameter(

                Terrasoft.ComparisonType.EQUAL, "Id", activityId));

updateQuery.setParameterValue("Status",

                ConfigurationConstants.Activity.Status.Cancel,

                this.Terrasoft.DataValueType.LOOKUP);

updateQuery.execute(function() {

        this.loadActivities();

}, this);

Удаление по словам "Terrasoft.DeleteQuery", примеров так же очень много, вот из DocumentRelationshipDetailV2:

var deleteQuery = this.Ext.create("Terrasoft.DeleteQuery", {

        rootSchemaName: "DocumentRelationship"

});

var masterRecordId = this.get("MasterRecordId");

var filters = this.getDeleteRelationFilters(masterRecordId, selectedRows);

deleteQuery.filters.add("DocumentsFilter", filters);

deleteQuery.execute(function() {

        this.hideBodyMask();

        this.deselectRows();

        this.reloadGridData();

}, this);


Большое спасибо!

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

Как обновить приложение с версии 7.8.2 на с 7.8.3

Не могу найти документацию.

Нравится

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

Добрый день, Максим!

Документацию по обновлению системы Вы найдете по ссылке:
https://academy.terrasoft.ru/documents/instrukciya-po-obnovleniyu-bpmon…

За необходимым дистрибутивом Вам необходимо обратиться в службу поддержки:
support@terrasoft.ru

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

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

Есть определенный интерес поизучать классы 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.

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

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

Здравствуйте, изучил тему по ссылке. В частности последний пост.
Возник ряд вопросов:
- Как правильно использовать dbExecutor для избежания утечки памяти?
- В каких именно случаях нужно пользоваться указанным в теме подходом?
- Всегда ли нужно оборачивать методы Execute() и ExecuteScalar() классов Select, Insert, Update в using, если нет, то в каких случаях это не обязательно?

Используемые версии приложения - от 7.4 и выше

Нравится

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

продублирую пост из ссылки в данную тему:

"Венжик Игорь" написал:Часто возникает ситуация когда необходимо сделать специфичечкий запрос к БД, который невозможно или сложно воспроизвести с помощью бизнес-сущностей. Например запросы к таблицам прав доступа, к системным таблицам. (Не законченная статья...)

В таких случая необходимо строить кастомные запросы:

Select select =
        new Select(UserConnection)
                .Column("Id")
                .Column("SysSchemaId")
                .Column("Name")
                .Column("SysSchemaManagerName")
                .Column("SysSchemaFolderId")
                .Column("MetaDataModifiedOn")
        .From("VwSysSchemaInSolution")
        .Where("SysSolutionId").IsEqual(new QueryParameter("solutionId", userConnection.Solution.Id))
                .And("SysSchemaId").In(schemas)
                .And("SysSchemaStateInSolution").IsNotEqual(Column.Const((int)StoringObjectState.Deleted))
                .And().OpenBlock("LockedById").IsNull()
                        .Or("LockedById").IsEqual(new QueryParameter("currentUserId", userConnection.CurrentUser.Id))
                .CloseBlock()
                as Select;
Для выполнения запросов к БД в нашей системе есть специальный объект DBExecutor. Экземпляр которого содержится в каждом UserConnection-е. То есть одному пользователю всегда доступен только один экземпляр DBExecutor-а, и пользователь не может сам создавать новые экземпляры.
Что бы получить экземпляр DBExecutor-а необходимо вызвать метод UserConnection.EnsureDBConnection().
using (var dbExecutor = UserConnection.EnsureDBConnection()) {

}
Для вызова всегда необходимо использовать конструкцию using!

Давайте раcсмотрим несколько вариантов работы

Допустим нам необходимо выполнить простой запрос:

Select select =
        new Select(UserConnection)
                .Column("Name")
        .From("Contact")
        .Where("City").IsEqual(Column.Parameter("Киев"))

Получение значения из первой строки, первого столбца выборки

Есть два способа

var name = select.ExecuteScalar();
или
string name;
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
        name = select.ExecuteScalar(dbExecutor);
}
Оба способа вернут один и тот же результат. Если вы выполняете одиночный запрос тогда используйте первый вариант, он является оберткой над вторым. Второй вариант, с передачей dbExecutor-а, будет полезен если выполнять несколько запросов к БД в рамках одной транзакции.

Получение списка значений:

List names = new List();
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
        using (var reader = select.ExecuteReader(dbExecutor)) {
                while(reader.Read()) {
                        int columnOrdinal = reader.GetOrdinal("Name");
                        names.Add(reader.GetString(columnOrdinal));
                }
        }
}

Выполнение запроса в рамках транзакции:

Оба запроса в базу будут выполнены в рамках транзакции и в случае свала транзакция откатится.

List names = new List();
using (var dbExecutor = UserConnection.EnsureDBConnection()) {

>>      dbExecutor.StartTransaction();
       
        using (var reader = select.ExecuteReader(dbExecutor)) {
                while(reader.Read()) {
                        int columnOrdinal = reader.GetOrdinal("Name");
                        names.Add(reader.GetString(columnOrdinal));
                }
        }
        insert.Execute(dbExecutor);

>>      dbExecutor.CommitTransaction();

}
Транзакция начинается вызовом метода dbExecutor.StartTransaction и заканчивается вызовом CommitTransaction или RollbackTransaction. В случае когда выполнение вышло за область видимости блока using и CommitTransaction не был вызван, происходит автоматический откат транзакции. Таким образом нет необходимости оборачивать транзакцию в try/catch блок, т.к. если был свал во время выполнения транзакция автоматически откатится.

Внимание! В текущей реализации даже если не передавать dbExecutor в метод Execute(), все равно запрос будет выполнен в текущей транзакции, если такая существует. Но для избежания сложностей в будущем, всегда при выполнении нескольких запросов в рамках транзакций - всегда передавайте dbExecutor в методы Execute, ExecuteReader, ExecuteScalar.

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

Методы Execute() и ExecuteScalar() классов Select, Insert, Update в using оборачивать не нужно.
Для Select-ов ExecuteScalar или Execute, который принимает анонимный метод - также не стоит оборачивать в using.
Для Select-а, который использует конструкцию List names необходимо использовать Using:

List names = new List();
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
using (var reader = select.ExecuteReader(dbExecutor)) {
while(reader.Read()) {
int columnOrdinal = reader.GetOrdinal("Name");
names.Add(reader.GetString(columnOrdinal));
}
}
}

Добрый день! Давно и сильно интересует вопрос, каким образом обернуть в транзакцию событийный процесс объекта при сохранении/удалении? Для гарантированной согласованности данных в разных сущностях, когда изменения в одном объекте влекут изменения в другом связанном.

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

Здравствуйте!
Можно ли в JS отключить учет прав при update,insert c использованием ESQ?

Нравится

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

Александр, ESQ задумывалась как раз в контексте работы с правами доступа.

Александр, без проверки вроде бы можно только на сервере, с клиентской части это довольно небезопасно.

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

Данная возможность отсутствует, для этого Вы можете использовать объект Select() на стороне сервера

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

"Андрей Каспаревич" написал:

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


Уже так и сделал. Спасибо.

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

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

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

Нравится

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

Если существует необходимость обработки событий объект, то Update лучше всего сделать через ESQ

public static void ExampleUpdateEntity(Guid contactId)
{
    EntitySchema schema = UserConnection.EntitySchemaManager.GetInstanceByName("Contact");
    EntitySchemaQuery esq = new EntitySchemaQuery(schema);
    esq.AddAllSchemaColumns();
    Entity entity = esq.GetEntity(UserConnection, contactId);
    entity.SetColumnValue("Name", "New Name");
    entity.Save();
}

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

Можно заменить и фильтрами. Сама идея просто работать с Entity.

    EntitySchema schema = UserConnection.EntitySchemaManager.GetInstanceByName("Contact");
    EntitySchemaQuery esq = new EntitySchemaQuery(schema);
    esq.AddAllSchemaColumns();
    esq.Filters.Add(esq.CreateFilterWithParameters(FilterComparisonType.Equal, "Name", "FilterName"));
    EntityCollection entities = esq.GetEntityCollection(UserConnection);
    foreach (Entity entity in entities)
    {
        entity.SetColumnValue("Name", "NewName");
        entity.Save();
    }

Спасибо за подсказку, все работает.

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

Добавил новое поле в [tbl_Contact], ссылка на [tbl_ConfigurationItemLocation]. Добавил это поле в sq_, ds_. В событиях SelfOnDatasetBeforePost, SelfOnDatasetAfterPost видно, что DataSet получает новое значение поля и флаг Change у DataField стоит, но в БД данные не уходят. Профайлер показывает, что update не содержит нового поля. Если открыть ds и выгрузить sql update, то в конструкции присутствует новое поле. Какой механизм задействован в генерации sql update и подстановки измененных параметров? Что может повлиять, на то что бы изменения не попадали в этот механизм?


P.S. хм, теперь в ds в select есть поле в update нет поля. Почему поле не попадает в update?
P.P.S. вопрос решен, в sq был выбран PK tbl_ConfigurationItemLocation.

Нравится

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

Здравствуйте, Михаил Евгеньевич!

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

Приятного дня!

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

В процессе администрирования базы данных возникла необходимость определить причину возникновения ошибки. Определенный объём информации импортируется в базу данных, с которым далее пользователи работают. В процессе заполнения определенного набора полей автоматически высчитывалась итоговая сумма в поле «Итого». Но в определённый промежуток времени использования продукта начали появляться ошибки, связанные с несоответствием значения поля «Итого» сумме полей из которых оно вычисляется («Сумма покупки», «Наценка», «Сбор» и т.д.). Так как ошибку не получалось явно повторить, необходимо было разработать механизм для решения данной проблемы.

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

В основу решения было положено создание двух таблиц в базе данных для ведения логов, что происходят с записью набора данных. Первая таблица WindowLog, а вторая TriggerLog.

Первая таблица WindowLog включает в себя поля «Дата создания»(CreatedOn), «Идентификатор записи» (RecordID), «Ответственный» (WindowsUser), «Имя поля породившего событие»(FieldName), «Итого» и поля из которых оно вычисляется («Сумма покупки», «Наценка», «Сбор» и т.д.). Для наполнения таблицы было использованы события невизуального компонента окна dlData: dlDataOnDatasetDataChange, dlDataOnDatasetBeforePost и dlDataOnDatasetAfterPost. В скрипте в событиях была создана функция, которая формировала SQL запрос к таблице WindowLog базы данных с фиксацией информации по указанным полям на момент срабатывания события.

Запрос:

INSERT INTO WindowLog (*набор полей*)
SELECT (*набор полей*) -- Dataset('поле1'), Dataset('поле2'), Dataset('поле2')

Вторая таблица TriggerLog включает в себя поля «Дата создания»(CreatedOn), «Идентификатор записи» (RecordID), «Состояние» (до изменения записи и после), «SystemUser», «Итого» и поля из которых оно вычисляется («Сумма покупки», «Наценка», «Сбор» и т.д.). Для заполнения данной таблицы был создан триггер на инструкцию UPDATE проблемной таблицы с двумя запросами вставки значений в таблицу. В одном запросе вставлялись значения до изменений, а во втором после.

Запрос №1:

INSERT INTO TriggerLog (*набор полей*)       
SELECT (*набор полей*)
FROM deleted

Запрос №2:

INSERT INTO TriggerLog (*набор полей*)       
SELECT (*набор полей*)
FROM inserted

Результатом использования данного решения на основе анализа таблицы WindowLog было установлено, что срабатывают все события окна редактирования, влияющие на вычисление значения поля «Итого». В процессе использования окна редактирования и после сохранения записи значения поля «Итого» были корректны.

Проанализировав записи в таблице TriggerLog было установлено, что в результате выполнения инструкции UPDATE было внесено некорректное значение. Сопоставив даты создания записей в таблице TriggerLog и WindowLog было установлено, что инструкция UPDATE была вызвана не в результате манипуляций с окном редактирования, а иным источником. На основании поля «SystemUser» таблицы TriggerLog было установлено что изменения были внесены с помощью импортера данных.

Таблицу TriggerLog возможно расширить, добавив в нее поля, которые помогут ускорить процесс обнаружение источника изменений записи базы данных. Список дополнительных полей может выгладять следующим образом: ApplicationName, LoginName, HostName.

PS: Принимаю предложения на доработку вашей конфигурации!!! Для более детальной информации можно связаться по следующему e-mail адресу: providnui@ukr.net !!!

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

Всем удачи в этом не легком процессе!!!

Нравится

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

Пытаюсь решить простую задачу - нужно в скрипте "обнулить" значение поля справочника. Поле не обязательное для заполнения, значение отличное от null в него записать удается, а вот как стереть из него все?

update = new Update(Page.UserConnection, "ConsignmentCargo")
        .Set("CurrentRoutePointId", Column.Parameter(DBNull.Value))
        .Where("IsLast").IsNotEqual(Column.Parameter(1))
        .And("ConsignmentId").IsEqual(Column.Parameter(CurrentConsignmentId));
update.Execute();

В примере это поле CurrentRoutePointId.

Через entity также установить null не удается

var entitySchemaManager = Page.Schema.SchemaManagerProvider.GetManager("EntitySchemaManager") as Terrasoft.Core.Entities.EntitySchemaManager;
        var entitySchemaQuery = new EntitySchemaQuery(entitySchemaManager, "ConsignmentCargo");
        entitySchemaQuery.AddColumn("CurrentRoutePoint");
        entitySchemaQuery.Filters.Add(entitySchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Consignment", CurrentConsignmentId));
        entitySchemaQuery.Filters.Add(entitySchemaQuery.CreateFilterWithParameters(FilterComparisonType.NotEqual, "IsLast", 1));       
        var entities = entitySchemaQuery.GetEntityCollection(UserConnection);  
               
        foreach (var entity in entities) {
                entity.SetColumnValue("CurrentRoutePointId", Column.Parameter(Guid.Empty));
                entity.Save();
        }

Нравится

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

Александр, попробуйте так

Column.Parameter(null, "Guid")

Думаю, такие примеры тоже пригодятся

			var dbNull = DataTypeUtilities.ValueAsType<Guid>(DBNull.Value);
			Assert.AreEqual(Guid.Empty, dbNull);
 
			var dbNull = DataTypeUtilities.ValueAsType<Guid>(null);
			Assert.AreEqual(Guid.Empty, dbNull);
 
			var dbNull = DataTypeUtilities.ValueAsType<DateTime>(DBNull.Value);
			Assert.AreEqual(DateTime.MinValue, dbNull);
 
			var dbNull = DataTypeUtilities.ValueAsType<DateTime>(null);
			Assert.AreEqual(DateTime.MinValue, dbNull);

"Раловец Ольга" написал:

Александр, попробуйте так

Column.Parameter(null, "Guid")


Сработало, спасибо!

"Александр Кудряшов" написал:

.Where("IsLast").IsNotEqual(Column.Parameter(1))


Александр, такой код не переносим на Oracle. К сожалению, или к с частью :), mssql очень много "додумывает" за разработчика и неявно приводит типы данных. Но Oracle не сможет интерпретировать 1 как true. Поэтому лучше написать:

.Where("IsLast").IsNotEqual(Column.Parameter(true, "Boolean"))
Показать все комментарии