После недавнего обновления Win10 (KB4056892), в Terrasoft 3.4.0.130 перестал отображаться пользователь в верхней части окна, отсутствуют напоминания и при переходе во вкладку Сделки появляется ошибка(та, что на скриншоте). Возможно кто-то сталкивался? Если обновление удалить все работает.
Этот сбой возникает на 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 на из клиентской части)
// Создание экземпляра запроса, добавление в запрос колонок и источника данных.
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"];
Здравствуйте.
Если сайт у вас развернуть 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, если нет, то в каких случаях это не обязательно?
"Венжик Игорь" написал:Часто возникает ситуация когда необходимо сделать специфичечкий запрос к БД, который невозможно или сложно воспроизвести с помощью бизнес-сущностей. Например запросы к таблицам прав доступа, к системным таблицам. (Не законченная статья...)
В таких случая необходимо строить кастомные запросы:
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));
}
}
}
Добрый день! Давно и сильно интересует вопрос, каким образом обернуть в транзакцию событийный процесс объекта при сохранении/удалении? Для гарантированной согласованности данных в разных сущностях, когда изменения в одном объекте влекут изменения в другом связанном.
Я понимаю, но есть задача,права в которой весьма противоречивы. Программно должно добавляться, а вручную нет. На сервер перенести задачу нельзя. Возможно ли это как-то реализовать?
Александр, можно на сервере создать конфигурационный веб-сервис и при необходимости посылать с клиента запрос на него. Таким образом получится реализовать задачу.
Александр, можно на сервере создать конфигурационный веб-сервис и при необходимости посылать с клиента запрос на него. Таким образом получится реализовать задачу.
а можно ли contactId как-то заменить фильтрами? Либо нужно сначала получить Id необходимой записи, а потом его использовать?
Каким образом можно после обработки обновить значения в карточке(перетянуть значения из базы, не обновляя страницу)?
Добавил новое поле в [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.
В процессе администрирования базы данных возникла необходимость определить причину возникновения ошибки. Определенный объём информации импортируется в базу данных, с которым далее пользователи работают. В процессе заполнения определенного набора полей автоматически высчитывалась итоговая сумма в поле «Итого». Но в определённый промежуток времени использования продукта начали появляться ошибки, связанные с несоответствием значения поля «Итого» сумме полей из которых оно вычисляется («Сумма покупки», «Наценка», «Сбор» и т.д.). Так как ошибку не получалось явно повторить, необходимо было разработать механизм для решения данной проблемы.
Естественно самой реальной и первой причиной возникновения такой ошибки приходила идея о сбоях в работе событий полей окна редактирования (то есть значения в полях изменялись, а события данных полей(-я) не срабатывали).
В основу решения было положено создание двух таблиц в базе данных для ведения логов, что происходят с записью набора данных. Первая таблица WindowLog, а вторая TriggerLog.
Первая таблица WindowLog включает в себя поля «Дата создания»(CreatedOn), «Идентификатор записи» (RecordID), «Ответственный» (WindowsUser), «Имя поля породившего событие»(FieldName), «Итого» и поля из которых оно вычисляется («Сумма покупки», «Наценка», «Сбор» и т.д.). Для наполнения таблицы было использованы события невизуального компонента окна dlData: dlDataOnDatasetDataChange, dlDataOnDatasetBeforePost и dlDataOnDatasetAfterPost. В скрипте в событиях была создана функция, которая формировала SQL запрос к таблице WindowLog базы данных с фиксацией информации по указанным полям на момент срабатывания события.
Вторая таблица TriggerLog включает в себя поля «Дата создания»(CreatedOn), «Идентификатор записи» (RecordID), «Состояние» (до изменения записи и после), «SystemUser», «Итого» и поля из которых оно вычисляется («Сумма покупки», «Наценка», «Сбор» и т.д.). Для заполнения данной таблицы был создан триггер на инструкцию UPDATE проблемной таблицы с двумя запросами вставки значений в таблицу. В одном запросе вставлялись значения до изменений, а во втором после.
Запрос №1:
INSERTINTO TriggerLog (*набор полей*) SELECT(*набор полей*) FROM deleted
Запрос №2:
INSERTINTO TriggerLog (*набор полей*) SELECT(*набор полей*) FROM inserted
Результатом использования данного решения на основе анализа таблицы WindowLog было установлено, что срабатывают все события окна редактирования, влияющие на вычисление значения поля «Итого». В процессе использования окна редактирования и после сохранения записи значения поля «Итого» были корректны.
Проанализировав записи в таблице TriggerLog было установлено, что в результате выполнения инструкции UPDATE было внесено некорректное значение. Сопоставив даты создания записей в таблице TriggerLog и WindowLog было установлено, что инструкция UPDATE была вызвана не в результате манипуляций с окном редактирования, а иным источником. На основании поля «SystemUser» таблицы TriggerLog было установлено что изменения были внесены с помощью импортера данных.
Таблицу TriggerLog возможно расширить, добавив в нее поля, которые помогут ускорить процесс обнаружение источника изменений записи базы данных. Список дополнительных полей может выгладять следующим образом: ApplicationName, LoginName, HostName.
PS: Принимаю предложения на доработку вашей конфигурации!!! Для более детальной информации можно связаться по следующему e-mail адресу: providnui@ukr.net !!!
В случае возникновения дополнительных вопрос по теме могу поделиться более детальной информацией.
Пытаюсь решить простую задачу - нужно в скрипте "обнулить" значение поля справочника. Поле не обязательное для заполнения, значение отличное от null в него записать удается, а вот как стереть из него все?
Александр, такой код не переносим на Oracle. К сожалению, или к с частью :), mssql очень много "додумывает" за разработчика и неявно приводит типы данных. Но Oracle не сможет интерпретировать 1 как true. Поэтому лучше написать: