Вывод редультата SQL запроса в новую WEB форму

Доброго времени суток. В ходе внедрения BPM online была поставлена задача выводить результаты sql запроса на отдельную страницу. т.е. имеем созданную по средствам BPM страницу, на странице есть поле ФИО кнопка поиск и еще несколько полей (например телефон и дата рождения). Вопрос номер 1: как сделать так что бы при нажатии на кнопку поиска, открывалась новая страница с результатами sql скрипта привязанного к этой кнопке. Вопрос номер 2: как реализовать перенос данных из 2-й формы в первую, если мы двойным кликом выделим один из результатов нашего запроса.
Что-то похожее реализовано в карточке регистрации пользователя, когда выбираем фио пользователя из карточки контакты. Спасибо.

Нравится

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

Здравствуйте, Александр. Опишите бизнес-задачу, которая перед Вами стоит. Насколько я понял, Вам необходимо осуществлять выбор из предварительно отфильтрованного справочника. Если Вы уже знаете, как добавлять поля справочного типа, обратитесь к этой статье. В ней описан способ наложения фильтрации на справочное поле.

есть связанный сервер, и в MSSQLе создано представление из нескольких таблиц из связанного сервера. есть sql скрипт который делает выборку из от этого представления. есть реестр регистрации обращений с кнопкой добавит, на кнопку привязана карточка регистрации нового обращения(назовем ее форма 1), в ней есть поля ФИО, дата рождения, номер телефона, адрес, остаток средств и кнопки поиск и добавить(плюс статусы, комментарии и т.д. - то есть поля которые заполняются вручную). есть вторая карточка(результаты запроса - форма 2) со списком полей (ФИО, дата рождения, номер телефона, адрес, остаток средств).
сам процесс: обращается клиент, добавляем новую запись, в первой форме в фио вводим к примеру иванов и жмем поиск, начинает отрабатывать sql скрипт который ищет всех ивановых в созданном предоставлении и результаты работы скрипта выводятся в форму 2. двойным кликом или по кнопке выбрать выбираем нужного нам иванова, все данные выбранного нами иванова из формы 2 переносятся в форму 1, после чего в форме один заполняем оставшиеся поля вручную и нажимаем кнопку добавить. после этого создается запись в реестр и все данные передаются в связанный сервер (в другую бд) для формирования документа и дальнейшей обработки информации.

Здравствуйте, Александр!
Вы говорите о создании справочного поля и наложении фильтрации для других полей (в зависимости от значения справочного поля).
Я правильно понял?
Если так, то никаких дополнительных страниц не нужно.

Нет, поля не справочные, хотя нужные данные хранятся в справочниках. Три текстовых поля. Вводим в каждое некий текст, нажимаем на созданную на форме кнопку поиск. Результат поиска получаем в отдельном окне.Пока вариант такой. Если знаете как лучше -подскажите, поиск должен проводиться по нескольким полям сразу. Про фильтры на странице выбора из справочника знаем, но нас такой вариант не устраивает. на скринах примерные формы, в первой форме в поле "фамилия" вводим иванов, в поле "имя отчество" александр и нажимаем поиск, результат выводится в форму на втором скрине и по дабл клику данные из второй формы должны заполнить поля в первой.

Александр, в таком случае можно открывать окно справочника с наложением своих фильтров.
Это можно делать с помощью действия. Посмотрите этот комментарий, есть пример открытия страницы справочника.

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

Александр, при чем тут бабушки?
Я имею ввиду по нажатию на кнопку открывать страницу справочника (второй скрин) с наложением фильтров по нужным полям. Значения берутся из полей на текущей карточке (первый скрин). По выбору значения обрабатывать событие и заполнять нужные поля.
Все соответсвует требованиям. Пользователю нужно будет ввести имя и фамилию, например, и нажать на кнопку, и отобразится отфильтрованный справочник.

спасибо за идею, попробуем.
ps: я думал про стандартные фильтры справочника настраиваемые вручную

Посмотрели комментарий. А нельзя ли поподробнее код расписать, в частности откуда брать значения строковых параметров (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 чего(объекта, страницы, справочника)?

C SSDocumentOfferingtId разобралиь, в данном случае это UID Объекта(таблицы из которой выбираем данные).

Следующий вопрос: как даблкликом перенести данные из окна результатов поиска обратно в форму запроса?
Спасибо за помощ.

Здравствуйте, Александр!
Это делается в скрипте после действия.
Функция

OpenSpecOfferingLookupUserTask.GetSelectedValues(UserConnection) as Dictionary <string, object>;

в примере получает выделенную запись, точнее идентификатор.
Получив его, можно, например, запросом в БД (EntitySchemaQuery) выбрать необходимую запись и вставить значения в соответсвующие поля.

А поподробнее можно? Как найденные значения определенных колонок справочника перенести в контролы на нашей форме.Скажем есть 3 параметра для фильтрации, нашли запись по 2 из них. Как в все три найденные значения перенести в первую форму(форму с нашими контрлами). Колонки справочника отличные от "Название" и "Описание".

Александр, с помощью EntitySchemaQuery получаете необходимую запись из объекта, и заносите значения полей этой записи в поля карточки. Вы ведь из справочника выбираете одну запись, правильно?
Как работать с EntitySchemaQuery описано здесь.
Плюс с помощью поиска по Community и в конфигурации можно найти множество примеров.

[/quote]

"Андрей Каспаревич" написал:Здравствуйте, Александр!
Это делается в скрипте после действия.
Функция
OpenSpecOfferingLookupUserTask.GetSelectedValues(UserConnection) as Dictionary ;

в примере получает выделенную запись, точнее идентификатор.
Получив его, можно, например, запросом в БД (EntitySchemaQuery) выбрать необходимую запись и вставить значения в соответсвующие поля.

Дописали в этот скрипт следующее :

Page.TextEdit2.SetValue(offeringId);

Все компилируется без ошибок, но TextEdit2 заполняется нулями сразу после нажатия кнопки поиск.
На данный момент на кнопке поиск висит следующий событийный подпроцесс:
процесс
PrepareScript:

var SSDocumentOfferingtId = "2bba6de9-51eb-43ca-a67a-a0761b7357e4";
Collection<Dictionary<string, object>> filters = new Collection<Dictionary<string, object>>();
filters.Add(new Dictionary<string, object> {
    {"comparisonType", FilterComparisonType.StartWith},
    {"leftExpressionColumnPath", "LAST_NAME"},
    {"useDisplayValue", false},
    {"rightExpressionParameterValues", new object[] {Page.TextEdit1.Value}}
 
});
filters.Add(new Dictionary<string, object> {
    {"comparisonType", FilterComparisonType.StartWith},
    {"leftExpressionColumnPath", "IO_NAME"},
    {"useDisplayValue", false},
    {"rightExpressionParameterValues", new object[] {Page.TextEdit2.Value}}
 
});     
filters.Add(new Dictionary<string, object> {
    {"comparisonType", FilterComparisonType.Contain},
    {"leftExpressionColumnPath", "PHONE"},
    {"useDisplayValue", false},
    {"rightExpressionParameterValues", new object[] {Page.TextEdit3.Value}}
 
});     
UserTask1.ProcessKey = InstanceUId;
UserTask1.PageParameters = new Dictionary<string, object>() {
    {"LookupFilters", filters},
    {"schemaUId", SSDocumentOfferingtId},
    {"customClosedEvent", "SpecOfferingLookupPageClosed"} //Сообщение при закрытии окна
};
UserTask1.UseCurrentActivePage = true;
return true;

Выполнить задание сценарий 2:

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);
return true;

Здравствуйте, Александр!
Дело в том, что действие считается выполненным, как только открывается страница.
Для решения проблемы необходимо вставить перед вторым скриптом вставить сигнал "Промежуточное обрабатывающее сообщение", которым "ловить" сообщение закрытия окна (в данном примере это "SpecOfferingLookupPageClosed"). Если так не сработает, удалите строку

 {"customClosedEvent", "SpecOfferingLookupPageClosed"}

, а после определения "PageParameters" добавьте:

UserTask1.CloseMessage = "SpecOfferingLookupPageClosed";

Пример можно посмотреть в "AccountEditPage", действие подписано "Открыть Страницу Результатов Поиска Дублей".

Здравствуйте Андрей, первый вариант сработал, спасибо, 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);
return true;

По дабл клику в форме она закрывается с ошибкой

Action: ThrowClientEvent
SubmitAjaxEventConfig: {"config":{"viewStateMode":"include","extraParams":{"processInstanceId":"e296e086-1397-48fd-82a5-d0cdeadeaa25PageContainer","message":"SpecOfferingLookupPageClosed","key":"06a180ff-e906-4a32-beb8-3db90394d02d"}}} 

Может есть какие-нибудь идеи?

Здравствуйте, Александр!
Эта ошибка начала появляться именно после добавления указанного кода?
Кроме кода обработчика Вы точно ничего не меняли?
Больше похоже на то, что не ловится событие закрытия окна.

Здравствуйте, Андрей. Ошибка стала вываливаться именно после добавления этого кода, если вернуть этот скрипт

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);
return true;

то все работает, Id вставляется в TextEdit2
ps: к предыдущему посту, форма закрывает, и открывается новое окошко с ошибкой.
Еррор

Александр, не могу точно определить, в чем дело.
Нужно посмотреть, что возвращает

var Items = DmsId.Value as Dictionary <string, object>;

Если самому решить не получится, советую обратиться в тех. поддержку.

Здравствуйте Андрей.
Сделали через EntitySchemaQuery. Все получилось. Но попутно возник еще один вопрос по поводу фильтра. В нашей таблице поле номер телефона может быть NULL. и если FilterComparisonType.Contain то записаи у которых поле PHONE NULL ны отображабтся в списке, как в даном скрипте моно поставить условие "или" Null?

filters.Add(new Dictionary<string, object> {
    {"comparisonType", FilterComparisonType.Contain},
    {"leftExpressionColumnPath", "PHONE"},
    {"useDisplayValue", false},
    {"rightExpressionParameterValues", new object[] {Page.TextEdit3.Value}}

Спасибо.

Вот пример из базовой конфигурации. Схема "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 для поля с выпадающим списком реализуется немного не так, как в лукап-поле. Отличие в аргументе функции:

PrepareLookupFilter += delegate (object sender, ComboBoxEditEventArgs e) {

Во-вторых, проверьте, точно ли там null, а не пустая строка, это разные вещи.
В-третьих, проблема из той темы актуальна для 5.1, так как там не было возможности указать "logicalOperation" для группировки фильтров.

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

Здравствуйте, Александр!

Во-первых, хочу обратить внимание, что PrepareLookupFilter для поля с выпадающим списком реализуется немного не так, как в лукап-поле. Отличие в аргументе функции:

PrepareLookupFilter += delegate (object sender, ComboBoxEditEventArgs e) {

Во-вторых, проверьте, точно ли там null, а не пустая строка, это разные вещи.

В-третьих, проблема из той темы актуальна для 5.1, так как там не было возможности указать "logicalOperation" для группировки фильтров.

С уважением,

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

Эксперт 3-й линии поддержки


Да в базе точно NULL. А вот из TextEdit3 если туда ничего не ввести передается не NULL. В любом случае прверка IsNull не отрабатывает. Может ли это быть связано с тем, что фильтруется справочник созданный на основе представления, созданного через linked server ?

Александр, думаю, что это не связано с 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''

Проверки на NULL нет, хотя в фильтре

filters.Add(new Dictionary<string, object> {
    {"comparisonType", FilterComparisonType.IsNull},
    {"leftExpressionColumnPath", "PHONE"},
    {"useDisplayValue", false},
	//{"rightExpressionParameterValues", new object[] {Page.TextEdit3.Value}}
 
})

Здравствуйте, Александр!
Могу предложить Вам другой вариант. По аналогии с тем, как накладывается фильтр на поле "RegionEdit" в карточке Контрагента, можно проверять содержимое поля, и, если оно не равно String.Empty, накладывать фильтр, иначе - не накладывать. Вот, как это сделано в карточке контрагента:

Page.RegionEdit.PrepareLookupFilter += PrepareRegionEditFilter;
 
 
public virtual void 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()}}});
		}

Мы так и планируем в будущем, но как из базы значения то получить , где PHONE=null ?

Александр, я попробовал на примере наложения фильтра на поле "CityEdit" так:

	filters.Add(new Dictionary<string, object> {
		{"comparisonType", FilterComparisonType.Equal},
		{"leftExpressionColumnPath", "Country.Id"},
		{"useDisplayValue", false},
		{"rightExpressionParameterValues", new object[] {countryId}}});
	filters.Add(new Dictionary<string, object> {
		{"comparisonType", FilterComparisonType.IsNull},
		{"leftExpressionColumnPath", "Country"},
		{"useDisplayValue", false}});
e.ParametersValue.Add("logicalOperation", LogicalOperationStrict.Or);

В иотге наложились оба фильтра с логическим объединением "ИЛИ". Вот такой запрос сформировался:

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.

Добрый день, Андрей. Спасибо за помощь. Реализовали данную проблему таким оброзом.

});  
if (!(p==null || p.ToString().Equals(string.Empty))){
filters.Add(new Dictionary<string, object> {
    {"comparisonType", FilterComparisonType.Contain},
    {"leftExpressionColumnPath", "PHONE"},
    {"useDisplayValue", false},
	{"rightExpressionParameterValues", new object[] {Page.TextEdit3.Value}}
 

Спасибо еще раз, и извиняюсь что не сразу отписались )

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