Доброго времени суток. В ходе внедрения BPM online была поставлена задача выводить результаты sql запроса на отдельную страницу. т.е. имеем созданную по средствам BPM страницу, на странице есть поле ФИО кнопка поиск и еще несколько полей (например телефон и дата рождения). Вопрос номер 1: как сделать так что бы при нажатии на кнопку поиска, открывалась новая страница с результатами sql скрипта привязанного к этой кнопке. Вопрос номер 2: как реализовать перенос данных из 2-й формы в первую, если мы двойным кликом выделим один из результатов нашего запроса. Что-то похожее реализовано в карточке регистрации пользователя, когда выбираем фио пользователя из карточки контакты. Спасибо.
Здравствуйте, Александр. Опишите бизнес-задачу, которая перед Вами стоит. Насколько я понял, Вам необходимо осуществлять выбор из предварительно отфильтрованного справочника. Если Вы уже знаете, как добавлять поля справочного типа, обратитесь к этой статье. В ней описан способ наложения фильтрации на справочное поле.
есть связанный сервер, и в MSSQLе создано представление из нескольких таблиц из связанного сервера. есть sql скрипт который делает выборку из от этого представления. есть реестр регистрации обращений с кнопкой добавит, на кнопку привязана карточка регистрации нового обращения(назовем ее форма 1), в ней есть поля ФИО, дата рождения, номер телефона, адрес, остаток средств и кнопки поиск и добавить(плюс статусы, комментарии и т.д. - то есть поля которые заполняются вручную). есть вторая карточка(результаты запроса - форма 2) со списком полей (ФИО, дата рождения, номер телефона, адрес, остаток средств).
сам процесс: обращается клиент, добавляем новую запись, в первой форме в фио вводим к примеру иванов и жмем поиск, начинает отрабатывать sql скрипт который ищет всех ивановых в созданном предоставлении и результаты работы скрипта выводятся в форму 2. двойным кликом или по кнопке выбрать выбираем нужного нам иванова, все данные выбранного нами иванова из формы 2 переносятся в форму 1, после чего в форме один заполняем оставшиеся поля вручную и нажимаем кнопку добавить. после этого создается запись в реестр и все данные передаются в связанный сервер (в другую бд) для формирования документа и дальнейшей обработки информации.
Здравствуйте, Александр!
Вы говорите о создании справочного поля и наложении фильтрации для других полей (в зависимости от значения справочного поля).
Я правильно понял?
Если так, то никаких дополнительных страниц не нужно.
Нет, поля не справочные, хотя нужные данные хранятся в справочниках. Три текстовых поля. Вводим в каждое некий текст, нажимаем на созданную на форме кнопку поиск. Результат поиска получаем в отдельном окне.Пока вариант такой. Если знаете как лучше -подскажите, поиск должен проводиться по нескольким полям сразу. Про фильтры на странице выбора из справочника знаем, но нас такой вариант не устраивает. на скринах примерные формы, в первой форме в поле "фамилия" вводим иванов, в поле "имя отчество" александр и нажимаем поиск, результат выводится в форму на втором скрине и по дабл клику данные из второй формы должны заполнить поля в первой.
Александр, в таком случае можно открывать окно справочника с наложением своих фильтров.
Это можно делать с помощью действия. Посмотрите этот комментарий, есть пример открытия страницы справочника.
Александр, при чем тут бабушки?
Я имею ввиду по нажатию на кнопку открывать страницу справочника (второй скрин) с наложением фильтров по нужным полям. Значения берутся из полей на текущей карточке (первый скрин). По выбору значения обрабатывать событие и заполнять нужные поля.
Все соответсвует требованиям. Пользователю нужно будет ввести имя и фамилию, например, и нажать на кнопку, и отобразится отфильтрованный справочник.
Посмотрели комментарий. А нельзя ли поподробнее код расписать, в частности откуда брать значения строковых параметров (Id документов, параметры фильтрации и т.д.). И как вообще его прикрутить к нашей странице, на какое событие вешать обработчик с кодом, как вытащить в код параметры из TextEditов. Если необходимо можем кинуть код нашей страницы.
PS: С# программиста у нас нет :(
Здравствуйте, Александр!
Обраобтчик вешается на кнопку на странице, где вводятся параметры для поиска.
Значения из TextEdit'ов берутся из свойства TextEdit'а "Value" таким образом:
var text = Page.TextEdit.Value;
UId объекта можно получить, открыв его метаданные (в разделе "Конфигурация"):
Есть много примеров наложения фильтрации и других действий в базовой конфигурации и здесь, на Comminty.
Можете посмотреть "ContactCareerEditPage", где открывается страница выбора из справочника по нажатию на кнопку "DepartamentButton".
Андрей добрый день, есть еще один вопросик, в примере в самом начале кода есть строка: var SSDocumentOfferingtId = new Guid(SysSettings.GetValue(UserConnection, "SSDocumentOfferingtId").ToString());//UID Объекта
можно подробнее описать что она делает? что в данном случае из себя представляет SSDocumentOfferingtId ? Это UID чего(объекта, страницы, справочника)?
Здравствуйте, Александр!
Это делается в скрипте после действия.
Функция
OpenSpecOfferingLookupUserTask.GetSelectedValues(UserConnection) as Dictionary <string, object>;
в примере получает выделенную запись, точнее идентификатор.
Получив его, можно, например, запросом в БД (EntitySchemaQuery) выбрать необходимую запись и вставить значения в соответсвующие поля.
А поподробнее можно? Как найденные значения определенных колонок справочника перенести в контролы на нашей форме.Скажем есть 3 параметра для фильтрации, нашли запись по 2 из них. Как в все три найденные значения перенести в первую форму(форму с нашими контрлами). Колонки справочника отличные от "Название" и "Описание".
Александр, с помощью EntitySchemaQuery получаете необходимую запись из объекта, и заносите значения полей этой записи в поля карточки. Вы ведь из справочника выбираете одну запись, правильно?
Как работать с EntitySchemaQuery описано здесь.
Плюс с помощью поиска по Community и в конфигурации можно найти множество примеров.
"Андрей Каспаревич" написал:Здравствуйте, Александр!
Это делается в скрипте после действия.
Функция
OpenSpecOfferingLookupUserTask.GetSelectedValues(UserConnection) as Dictionary ;
в примере получает выделенную запись, точнее идентификатор.
Получив его, можно, например, запросом в БД (EntitySchemaQuery) выбрать необходимую запись и вставить значения в соответсвующие поля.
Дописали в этот скрипт следующее :
Page.TextEdit2.SetValue(offeringId);
Все компилируется без ошибок, но TextEdit2 заполняется нулями сразу после нажатия кнопки поиск.
На данный момент на кнопке поиск висит следующий событийный подпроцесс:
var dmsres = UserTask1.GetSelectedValues(UserConnection) as Dictionary <string, object>;
var Id = Guid.Empty;
foreach (var dmsid in dmsres){
Id =new Guid (dmsid.Key.ToString());}
Page.TextEdit2.SetValue(Id);returntrue;
Здравствуйте, Александр!
Дело в том, что действие считается выполненным, как только открывается страница.
Для решения проблемы необходимо вставить перед вторым скриптом вставить сигнал "Промежуточное обрабатывающее сообщение", которым "ловить" сообщение закрытия окна (в данном примере это "SpecOfferingLookupPageClosed"). Если так не сработает, удалите строку
Здравствуйте Андрей, первый вариант сработал, спасибо, ID смогли вставить в TextEdit2. есть еще вопросик, на форуме нали вот такой скрипт:
var DmsRes = UserTask1.GetSelectedValues(UserConnection) as Dictionary <string, object>;
var Id = Guid.Empty;
var Lname = string.Empty;
foreach (var DmsId in DmsRes){
Id =new Guid (DmsId.Key.ToString());
var Items = DmsId.Value as Dictionary <string, object>;
Lname =Items["LAST_NAME"].ToString();}
Page.TextEdit2.SetValue(Lname);returntrue;
Здравствуйте, Александр!
Эта ошибка начала появляться именно после добавления указанного кода?
Кроме кода обработчика Вы точно ничего не меняли?
Больше похоже на то, что не ловится событие закрытия окна.
Здравствуйте, Андрей. Ошибка стала вываливаться именно после добавления этого кода, если вернуть этот скрипт
var dmsres = UserTask1.GetSelectedValues(UserConnection) as Dictionary <string, object>;
var Id = Guid.Empty;
foreach (var dmsid in dmsres){
Id =new Guid (dmsid.Key.ToString());}
Page.TextEdit2.SetValue(Id);returntrue;
то все работает, Id вставляется в TextEdit2
ps: к предыдущему посту, форма закрывает, и открывается новое окошко с ошибкой.
Здравствуйте Андрей.
Сделали через EntitySchemaQuery. Все получилось. Но попутно возник еще один вопрос по поводу фильтра. В нашей таблице поле номер телефона может быть NULL. и если FilterComparisonType.Contain то записаи у которых поле PHONE NULL ны отображабтся в списке, как в даном скрипте моно поставить условие "или" Null?
Вот пример из базовой конфигурации. Схема "Activity", метод "RecalculateWorkingTimeForServiceRequest()":
var entitySchemaManager = UserConnection.GetSchemaManager("EntitySchemaManager") as EntitySchemaManager;
var activitySchemaQuery =new EntitySchemaQuery(entitySchemaManager, "Activity");
var startQueryColumnName = activitySchemaQuery.AddColumn("StartDate").Name;
var dueQueryColumnName = activitySchemaQuery.AddColumn("DueDate").Name;
var incidentFilter = activitySchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Incident", serviceRequestId);
var serviceCallFilter = activitySchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "ServiceCall", serviceRequestId);
var filter =new EntitySchemaQueryFilterCollection(activitySchemaQuery, LogicalOperationStrict.Or, incidentFilter, serviceCallFilter);
activitySchemaQuery.Filters.Add(filter);
Или можно воспользоваться методом, как в этой теме.
Вот пример из базовой конфигурации. Схема "Activity", метод "RecalculateWorkingTimeForServiceRequest()":
var entitySchemaManager = UserConnection.GetSchemaManager("EntitySchemaManager") as EntitySchemaManager;
var activitySchemaQuery = new EntitySchemaQuery(entitySchemaManager, "Activity");
var startQueryColumnName = activitySchemaQuery.AddColumn("StartDate").Name;
var dueQueryColumnName = activitySchemaQuery.AddColumn("DueDate").Name;
var incidentFilter = activitySchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Incident", serviceRequestId);
var serviceCallFilter = activitySchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "ServiceCall", serviceRequestId);
var filter = new EntitySchemaQueryFilterCollection(activitySchemaQuery, LogicalOperationStrict.Or, incidentFilter, serviceCallFilter);
activitySchemaQuery.Filters.Add(filter);
Или можно воспользоваться методом, как в этой теме.
С уважением,
Каспаревич Андрей
Эксперт 3-й линии поддержки
Вариант не очень подходящий. Проблема такая же как в этой теме, но предложенный там вариант использовать не хотелось бы (очень много записей тянется). И попутно возникла вторая проблема, если в PrepareLookupFilter comparisonType заменить на IsNull, то записи с NULL в нужной колонке не подтягиваются
Здравствуйте, Александр!
Во-первых, хочу обратить внимание, что PrepareLookupFilter для поля с выпадающим списком реализуется немного не так, как в лукап-поле. Отличие в аргументе функции:
Во-вторых, проверьте, точно ли там null, а не пустая строка, это разные вещи.
В-третьих, проблема из той темы актуальна для 5.1, так как там не было возможности указать "logicalOperation" для группировки фильтров.
Во-первых, хочу обратить внимание, что PrepareLookupFilter для поля с выпадающим списком реализуется немного не так, как в лукап-поле. Отличие в аргументе функции:
Во-вторых, проверьте, точно ли там null, а не пустая строка, это разные вещи.
В-третьих, проблема из той темы актуальна для 5.1, так как там не было возможности указать "logicalOperation" для группировки фильтров.
С уважением,
Каспаревич Андрей
Эксперт 3-й линии поддержки
Да в базе точно NULL. А вот из TextEdit3 если туда ничего не ввести передается не NULL. В любом случае прверка IsNull не отрабатывает. Может ли это быть связано с тем, что фильтруется справочник созданный на основе представления, созданного через linked server ?
SELECT TOP 41[spisok].[Id][Id],
[spisok].[LAST_NAME][LAST_NAME],
[spisok].[IO_NAME][IO_NAME],
[spisok].[PHONE][PHONE]
FROM
[dbo].[spisok][spisok]
WHERE
([spisok].[LAST_NAME] LIKE N''%''+ @P1 + N''%''
AND [spisok].[IO_NAME] LIKE N''%''+ @P2 + N''%''
AND [spisok].[PHONE]= @P3)
ORDER BY
[Id] ASC',N'@P1 nvarchar(5),@P2 nvarchar(4000),@P3 nvarchar(4000)',@P1=N'бутор',@P2=N'',@P3=N''
Здравствуйте, Александр!
Могу предложить Вам другой вариант. По аналогии с тем, как накладывается фильтр на поле "RegionEdit" в карточке Контрагента, можно проверять содержимое поля, и, если оно не равно String.Empty, накладывать фильтр, иначе - не накладывать. Вот, как это сделано в карточке контрагента:
Page.RegionEdit.PrepareLookupFilter+= PrepareRegionEditFilter;publicvirtualvoid PrepareRegionEditFilter(object sender, LookupEditEventArgs e){
object value = Page.CountryEdit.Value;//получение значения
Guid countryId =(value == null || value.ToString().Equals(string.Empty))? Guid.Empty: Guid.Parse(value.ToString());//проверкаif(countryId == Guid.Empty){return;//если значение поля - пустая строка, выходим из метода}//наложение фильтров
var filters = e.Filters;
filters.Add(new Dictionary<string, object>{{"comparisonType", FilterComparisonType.Equal},
{"leftExpressionColumnPath", "Country.Id"},
{"useDisplayValue", false},
{"rightExpressionParameterValues", new object[]{countryId.ToString()}}});}
В иотге наложились оба фильтра с логическим объединением "ИЛИ". Вот такой запрос сформировался:
exec sp_executesql N'
SELECT TOP 41
[City].[Id] [Id],
[City].[Name] [Name]
FROM
[dbo].[City] [City]
WHERE
(EXISTS (
SELECT
[Country].[Id] [Id]
FROM
[dbo].[Country] [Country]
WHERE
[City].[CountryId] = [Country].[Id]
AND [Country].[Id] = @P1)
OR [City].[CountryId] IS NULL)
ORDER BY
[Name] ASC,
[Id] ASC',N'@P1 uniqueidentifier',@P1='A670B005-E8BB-DF11-B00F-001D60E938C6'
Это конечно замечательно, что у вас все работает, только почему не работает у нас? Даже если из кода, приведенного выше выкинуть первые два фильтра и просто попытаться вывести список записей со значением NULL в колонке PHONE, то ни одна запись не выводится. Как видно в SQL запросе, отправляемом на сервер проверка на NULL не производится.
Второе: у нас операция "или" не должна применяться ко всем фильтрам сразу, т.е. результирующий SQL запрос должен быть таким
SELECT TOP 41[spisok].[Id][Id],
[spisok].[LAST_NAME][LAST_NAME],
[spisok].[IO_NAME][IO_NAME],
[spisok].[PHONE][PHONE]
FROM
[dbo].[spisok][spisok]
WHERE
([spisok].[LAST_NAME] LIKE N''%''+ @P1 + N''%''
AND ([spisok].[IO_NAME] LIKE N''%''+ @P2 + N''%'' OR [spisok].[IO_NAME] IS NULL)
AND ([spisok].[PHONE]= @P3 OR [spisok].[PHONE] IS NULL)
ORDER BY
[Id] ASC',N'@P1 nvarchar(5),@P2 nvarchar(4000),@P3 nvarchar(4000)',@P1=N'бутор',@P2=N'',@P3=N''
Если нет никаких идей, не могли бы вы подключиться и посмотреть в чем может быть проблема.
Александр, а зачем вообще накладывать фильтр "ИЛИ" с проверкой пустых строк, если заведомо известно, что там null, а не пустая строка? Если в поле не введены данные, то логичнее было бы вообще не фильтровать по этому полю.
Как пользователь сможет получить нужную запись, если у нее заполнены все поля, но пользователь помнит только одно из них?
Можно предположить, что пользователь захочет получить все записи, у которых поле не заполнено. Для этого случая предлагаю добавить на страницу с полями ввода значений для фильтрации еще чек-боксы типа "Не заполнено". И, если установлена "галка", накладывать только фильтр IsNull.
Тема настройки веб-формы подымалась не один раз. И все же, в разных версиях Windows есть отличия. В данном блоге я хочу предоставить цикл поднятия веб-формы на операционных системах с ядром Windows 7 (Windows 7, Windows Server 2008 R2 и выше). И так, начнем с самого основного – компоненты Windows. В блоге предоставляется основной набор установленных компонентов Windows. Также, здесь описано как работать с веб-формой с помощью доменной авторизации. В связи с добавлением этой функциональности, список минимально необходимых компонентов расширяется.
Добавим/проверим список установленных компонентов
Добавим пользователя, который должен входить в группу IIS_IUsrs
Регистрируем Terrasoft от имени заведенного нами пользователя (в нашем случае – TSWebFormUser)
Настраиваем конфигурацию
Копирование Config.xml
После того, как конфигурация настроена и проверена, нам нужно скопировать файл с Config.xml из папки пользователя TSWebFormUser в папку Settings установленного Terrasoft’а
В моем случае Terrasoft установлен в папку C:\Terrasoft, поэтому я буду его копировать в C:\Terrasoft\Settings из папки пользователя С:\Users\TSWebFormUser\appdata\Roaming\Terrasoft\3.4.0\Settings
Редактирование RunSettings
Открываем файл RunSettings.xml (в моем случае C:\Terrasoft\Settings\RunSettings.xml) и указываем новый путь к файлу Config.xml
Открываем оснастку Internet Information Service (IIS) Manager
Проверяем ISAPI and CGI Restrictions
Если у вас в списке нету ASP NET v4.0.x, то необходимо установить Framework 4 (при установке скорее всего появится диалог Remove\Repair, нужно сделать Repair или из командной строки выполнить:
%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe –i
%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis.exe –i)
Добавляем новый Application Pool
Настраиваем запуск от имени нашего заведенного пользователя TSWebFormUser
Устанавливаем разрешение на запуск 32-х битных приложений (в 2008 R2 x64 у меня заработало без этого разрешения, но скорость меньше)
Добавляем приложение (именно приложение, Virtual Directory работать не будет) и указываем пользователя, от которого оно будет запускаться
Тестируем подключение
Добавляем страницу Login.aspx как страницу по умолчанию
В Application Settings настраиваем подключение к конфигурации
В секции TSLogin нужно указать пользователя, который имеет права на соответствующие разделы
На этом этапе Вы получаете работоспособную Web-форму, но без доменной авторизации. Для того чтобы включить доменную авторизацию необходимо:
Установить значение параметра TSAllowWindowsAuthentication в True
Авторизация
Анонимную авторизацию выключить, а Windows Authentication - включить (если она отсутствует в списке, то вы не выполнили 1-й пункт, а именно не включили компонент Windows Authentication)
Вот собственно все, что требуется для настройки Web-формы на Windows 7 и Windows 2008 R2