// Создание экземпляра запроса, добавление в запрос колонок и источника данных.
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.
var newSelect = new Select(CurrentUserConnection)
.Column("Table1", "Column1").As("Column1")
.From("Table1").As("Table1")
.Where("Table1", "Column2").IsNotEqual( ... ) as Select;
И имеется некоторая коллекция значений, к примеру:
List myList = new List();
Вопрос в следующем: Каким образом можно в условие запроса передать список значений моей коллекции (будь то Array, ArrayList, List, Dictionary, Hashtable, SortedList или другое - значения не имеет)?
Условно говоря, мне нужно мою коллекцию представить в виде типа "Select", чтобы можно было использовать в месте отмеченном 3-мя точками, - это если следовать сигнатуре этих методов, согласно описанию из SDK (www.terrasoft.ru/bpmonlinesdk/). Но как это сделать? Прошу помощи!
Виталий, для этого нужно использовать конструкцию .Not().In(массив_или_список_идентификаторов) .
Пример использования (схема EditSynchUserInSynchRole):
var ldapGroupsIds =new List<QueryParameter>();
var ldapUserLoginAttribute = SysSettings.GetValue(UserConnection, "LDAPUserLoginAttribute").ToString();using(var ldapUtils =new LdapUtilities(UserConnection)){
var usersCollection = ldapUtils.GetUsersAttributesByFilter(ldapUserLoginAttribute +"="+ ldapEntry, new[]{"distinguishedName"});
var userDn = string.Empty;
foreach (SearchResultEntry user in usersCollection){
userDn = user.DistinguishedName;break;}
var ldapGroupIdentityAttribute = SysSettings.GetValue(UserConnection, "LDAPGroupIdentityAttribute").ToString();
var groupsCollection = ldapUtils.GetGroupsAttributesByFilter("member="+ userDn, new[]{ldapGroupIdentityAttribute});
foreach(SearchResultEntry group in groupsCollection){
ldapGroupsIds.Add(new QueryParameter(ldapUtils.IdentityAttributeToString(group.Attributes[ldapGroupIdentityAttribute][0])));}}if(ldapGroupsIds.Count<1){returntrue;}
var delete=new Delete(UserConnection).From("SysUserInRole").
Where("SysUserId").IsEqual(Column.Parameter(userId)).
And().Exists(new Select(UserConnection).
Column("Id").From("SysAdminUnit").
Where("SysUserInRole", "SysRoleId").IsEqual("SysAdminUnit", "Id").
And("SynchronizeWithLDAP").IsEqual(Column.Parameter(true)).
And("LDAPEntryId").Not().In(ldapGroupsIds));delete.Execute();
Если же передавать массив, то так (схема AdministrativeGrantedRightsGridPage):
object[] objectParameters =new object[adminUnitCollection.Count];for(int i =0; i < adminUnitCollection.Count; i++){
objectParameters[i]= adminUnitCollection[i];}}
var entitySchemaManager = Page.UserConnection.EntitySchemaManager;
var rightsSchema = entitySchemaManager.GetInstanceByName("SysAdminUnitGrantedRight");
var select =new Select(Page.UserConnection)
.Column(rightsSchema.Name, "Id")
.Column(rightsSchema.Name, "GrantorSysAdminUnitId")
.Column("Grantor", "Name").As("GrantorSysAdminUnitName")
.From(rightsSchema.Name)
.InnerJoin("SysAdminUnit").As("Grantor").On("Grantor", "Id").IsEqual(rightsSchema.Name, "GrantorSysAdminUnitId")
.Where(rightsSchema.Name, "GranteeSysAdminUnitId").In(Column.Parameters(objectParameters))
.OrderByAsc("Grantor", "Name") as Select;
Я тоже думал, что только массивы из Object, но оказалось, что не только массивы.
В первом примере обратите внимание, что коллекция из элементов именно типа QueryParameter.
Верно ли это? Тогда я не смогу указать оператор "In()" для колонки, содержащую тип "Guid", т.к. я буду проверять наличие текущей записи в коллекции guids, а у нее QueryParameter содержит тип "string". Что-то тут нечисто... Подскажете, как быть?:confused:
Доброго времени суток, коллеги. Согласно этому в запросе в колонке с текстом SQL вроде как можно использовать конструкцию для автоматической замены таблицы на представление в зависимости от прав пользователя. Вопрос: в каких версиях Terrasoft это работает? На Terrasoft CRM 3.3.2.245 выдает ошибку "Оригинальное сообщение об ошибке: Incorrect syntax near ''. Incorrect syntax near the keyword 'SELECT'"
Добрый день! Подскажите, пожалуйста синтаксис запрос COUNT на C#
Например, такой запрос
var select =
new Select(userConnection)
.Column("SysUserInRole","SysUserId")
.From("SysUserInRole")
.Join(JoinType.Inner, "SysAdminUnit").On("SysUserInRole", "SysUserId").IsEqual("SysAdminUnit", "Id")
.Where("SysUserInRole", "SysRoleId").IsEqual(new QueryParameter(ownerGroup))
as Select;
я, наверное, не так выразилась
- хочу обратиться, результату значения из запроса
dataReader.GetColumnValue("NameCount")
NameCount"- это число (кол-во записей)
Илья, UserConnection - это класс ядра, который включает функции и свойства соединения пользователя (уникальные данные пользователя, сессии, временная зона).
Пример использования:
UserConnection.CurrentUser.Id// текущий пользователь
UserConnection.CurrentUser.ContactId// Контакт текущего пользователя
UserConnection.CurrentUser.AccountId// Контрагент текущего пользователя
UserConnection.CurrentUser.GetCurrentDateTime()// Текущие время в часовой зоне пользователя
Как написал Александр, чтобы использовать UserConnection, достаточно обратиться (без дополнительных объявлений).
"Соколов Илья Андреевич" написал:"userConnection" с маленькой буквы написан
Глобальный объект UserConnection доступен не везде. Если, например, пишем функцию в отдельной схеме вроде CommonUtilities, то его нужно передавать в функцию как параметр. При вызове функции будет с большой буквы, а параметр функции — с маленькой, чтобы не перепутать.
"Соколов Илья Андреевич" написал:В примерах www.terrasoft.ru/bpmonlinesdk/ "userConnection" с маленькой буквы написан и не хватает в примерах ...Execute(); Просьба добавить.
Илья, в примерах SDK основной целью было показать, как формировать различные виды запросов к БД. Выполнение экземпляра запроса вторичен в данных примерах.
В связи с описанной Вами необходимостью уточнить дальнейший порядок действий, будет добавлена информацию о том, как запускать команды на выполнение.
Обновленные статьи будут опубликованы в следующем запланированном обновлении SDK.
Нужно было вызвать Execute для insert.
Кроме того, ContactCommunication — деталь раздела контактов и в новой записи нужно заполнить связь ContactId и другие стандартные поля.
Екатерина, с примером вызова хранимой процедуры из скрипта Вы можете ознакомиться в процессе страницы BaseDuplicateMergeEditPage, а именно в OKButtonClickScriptTask:
В процессе администрирования базы данных возникла необходимость определить причину возникновения ошибки. Определенный объём информации импортируется в базу данных, с которым далее пользователи работают. В процессе заполнения определенного набора полей автоматически высчитывалась итоговая сумма в поле «Итого». Но в определённый промежуток времени использования продукта начали появляться ошибки, связанные с несоответствием значения поля «Итого» сумме полей из которых оно вычисляется («Сумма покупки», «Наценка», «Сбор» и т.д.). Так как ошибку не получалось явно повторить, необходимо было разработать механизм для решения данной проблемы.
Естественно самой реальной и первой причиной возникновения такой ошибки приходила идея о сбоях в работе событий полей окна редактирования (то есть значения в полях изменялись, а события данных полей(-я) не срабатывали).
В основу решения было положено создание двух таблиц в базе данных для ведения логов, что происходят с записью набора данных. Первая таблица 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 !!!
В случае возникновения дополнительных вопрос по теме могу поделиться более детальной информацией.
Здравствуйте! Требуется настроить планирование по работе менеджера. У менеджера есть задача обзвонить и назначить определенное количество встреч. Данная информация фиксируется через Задачи. Как сделать настройку планирования, чтобы данная настройка отображалась в Разделе Планирования?
Пробовал сделать, но почему то не вышло.
Сделал запрос по задачам, создал настройку планирования - в поле показатель выбрал поле Количество,которые сформировано в запросе из Заголовка, выбрал функцию "Сумма".
Мне кажется, не совсем правильно выбрал показатель в настройке планирования.
При нажатии кнопки "Пересчитать факт" в разделе планирования выдает ошибку
Сообщение об ошибке: Ошибка открытия источника данных "". Оригинальное сообщение об ошибке: Operand data type nvarchar is invalid for sum operator
Как вывести в настройки планирования фактическое количество Задач в показатель? И чтобы по этому показателю можно было формировать плановые данные?
Здравствуйте!
Настраиваю Планирование задач по примеру в демо версии. Смотрю количество задач по Ответственным. На детали Подробно для выбранного в списке ответственного отображается 4 задачи, при этом в колонке факт основной таблицы - 0,00.
Нажимаю "Пересчитать факт" ситуация сохраняется. В чем может быть причина?
Подскажите, есть ли подробное пошаговое руководство по созданию рассылки, начиная от создания запроса и до непосредственно процесса отправки?
В частности, интересуют следующие вопросы:
1. Действительно ли в качестве основной таблицы можно использовать только "Средства связи контакта" или "Средства связи контрагента"?
2. Нужно ли делать фильтр по полю Код ("Код" содержит "EMAIL")?
3. Обязательно ли создавать дополнительные детали? Или можно вынести поле "ФИО" из обратной связи в основную деталь?
4. Нужно ли в свойствах запроса выбирать поле фильтрации?
5. Нужно ли в шаблоне сообщения для рассылки заполнять деталь "Получатели"?
Дело в том, что по всем пунктам у меня "Да", но рассылка не уходит (Состояние = Ошибка). При этом не рассылочная почта из Terrasoft'a уходит нормально.
Если Вы когда-либо создавали запросы SelectQuery с CustomSQL-колонками, Вы наверняка обратили внимание на то, что запрос, прекрасно работающий под учетной записью администратора может оказаться нефункциональным под учетной записью пользователя, если в CustomSQLColumn используются таблицы, администрируемые по записям.
При этом обращение к тем же таблицам средствами дизайнера отчетов вполне успешно. В чем же секрет?
Дело в том, что если таблица администрируется по записям, дизайнер запросов при работе под пользователем автоматически подставляет вместо нее представление. А поскольку CustomSQL-колонки вставляются в запрос как есть, в результате у пользователя нет доступа к таблице, и есть доступ к предоставлению.
Схема работы:
Для того, чтобы запрос работал корректно, следует в CustomSQLColumn использовать не таблицу, а ее алиас, заданный в блоке FROM. В случае необходимости - присоединить таблицу в одном из JOIN-ов и также обращаться по алиасу.
Есть еще один способ - сразу указать в CustomSQLColumn представление таблицы. Однако такой способ медленнее, кроме того, запрос станет нефункциональным, если Вы отключите администрирование по записям.
В любом случае, при создании запроса в дизайнере постарайтесь все то, что можно реализовать минуя SQL-колонки сделать штатными средствами, и использовать их только для не реализуемых вычислений.
В том, что сделано при помощи дизайнера, разработчики могут добавить дополнительные проверки, а за запрос, написанный в CustomSQLColumn отвечаете лично Вы.
Есть еще один способ - сразу указать в CustomSQLColumn представление таблицы. Однако такой способ медленнее
Кроме того что он будет медленнее для Администратора, он еще почти всегда будет работать некорректно - так как будет проверяться доступ на записи, а как правило Администратору никто его не дает, он и так все "видит".
В случае добавления безобидной колонки Account.Name
И удалении прав на чтение этой колонки:
TSObjectLibrary.DBDataset: Ошибка открытия источника данных "ds_Account".
Оригинальное сообщение об ошибке: The SELECT permission was denied on the column 'Name' of the object 'vw_Account", database 'XXX', schema 'dbo'
Нет, это потому, что на нее доступ запрещен на уровне БД в самой таблице(и как следствие во вьюхе). Ядро в таком случае колонки заменяет на NULL, чтоб к ним вообще обращение не шло.
Пока мне известен один способ обхода - создавать отдельную функцию и использовать в CustomSQLColumn: