Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / FoxPro, Visual FoxPro Новый топик    Ответить
 Произвольное предложение WHERE в REMOTE VIEW...  [new]
___DenisKa
Guest
Всем привет!

Вначале опишу то, что дано:
есть справочник корреспондентов, состоящий из нескольких таблиц (предприятия; должности на этих предприятиях; сотрудники, занимающие эти должности и т.д.)
Для отображения этой информации используецца несколько remote view. Некоторые из них обновляемые и это их достоинство не хочецца терять .
Но данных ОЧЕНЬ много, посему если сразу все вываливать на клиента,
то справочник работает очень долго.
Посему хочу открывать справочник ПУСТЫМ, а потом пользователь сам укажет по каким критериям он хотел бы выбирать данные (отбор может проводицца по нескольким полям).
Для отбора использую свой объект, который на выходе выдает строку вида:
EnterpriseName like '%ООО%' and CityName like '%Новгород%' and Address like '%Горького%'

Подскажите плиз, многоуважаемые, можно ли добицца следующей вещи:
создать remote view (желательно ОБНОВЛЯЕМОЕ), которое бы выглядело примерно так:

CREATE SQL VIEW vAddress REMOTE CONNECTION conMain SHARE AS ;
SELECT * FROM vAddress ;
WHERE ?lcWhere

где в качестве lcWhere можно было бы подставить вышеуказанную строку фильтра?

ЗЫ если кто-то скажет, что данное view не будет обновляемым никогда, то оговорюсь, что это лишь пример, на самом деле есть remote view , выбирающие данные из одной таблицы и которые хочецца также параметризовать по нескольким произвольным полям этой таблицы...
2 окт 04, 14:01    [1003985]     Ответить | Цитировать Сообщить модератору
 Re: Произвольное предложение WHERE в REMOTE VIEW...  [new]
Igor Korolyov
Member

Откуда: Гомель, Беларусь
Сообщений: 2512

2 ___DenisKa

Эх, сложную ты очень тему поднимаешь :(

Попробую лишь очень кратко описать как я это делаю:

1) RV пишется с условием WHERE 1=1. Дальнейшее как обычно - т.е. поля назначаются ключевыми, обновляемыми и т.д.

2) Пользуются следующие 2 функции:

PROCEDURE Use_RV
LPARAMETERS tcViewName, tcAlias, tcWhere
LOCAL lcAlias, lcSQL, lnConnHandle, lcTables, ;
 lcKeyFieldList, lcUpdatableFieldList, lcUpdateNameList
m.lcAlias = m.tcAlias + "_template"
IF USED (m.lcAlias)
 USE IN (m.lcAlias)
ENDIF
DO CASE
CASE INDBC (m.tcAlias, "VIEW") AND ;
  DBGETPROP (m.tcAlias, "VIEW", "SOURCETYPE") = 1
 * Локальное представление
 LOCAL lcWhere
 m.lcWhere = m.tcWhere
 USE (m.tcViewName) IN 0 ALIAS (m.tcAlias) SHARED
 RETURN .T.
CASE INDBC (m.tcAlias, "TABLE")
 * Таблица
 USE (m.tcViewName) IN 0 ALIAS (m.tcAlias) SHARED
 RETURN .T.
ENDCASE

USE (m.tcViewName) IN 0 NODATA ALIAS (m.lcAlias)
* Извлекаем то что есть в RV
m.lcSQL = CURSORGETPROP ("SQL", m.lcAlias)
m.lnConnHandle = CURSORGETPROP ("ConnectHandle", m.lcAlias)
m.lcTables = CURSORGETPROP ("Tables", m.lcAlias)
m.lcKeyFieldList = CURSORGETPROP ("KeyFieldList", m.lcAlias)
m.lcUpdatableFieldList = CURSORGETPROP ("UpdatableFieldList", m.lcAlias)
m.lcUpdateNameList = CURSORGETPROP ("UpdateNameList", m.lcAlias)
IF USED (m.tcAlias)
 USE IN (m.tcAlias)
ENDIF
SELECT 0
IF " WHERE " $ UPPER (m.lcSQL)
 m.lnRes = SQLEXEC (m.lnConnHandle, ;
  STRTRAN (m.lcSQL, " WHERE " , " WHERE (" + m.tcWhere + ") AND ", ;
  1, 1, 1), m.tcAlias)
ELSE
 m.lnRes = SQLEXEC (m.lnConnHandle, m.lcSQL + " WHERE " + m.tcWhere, m.tcAlias)
ENDIF
IF m.lnRes < 1
 MESSAGEBOX ("Ошибка получения данных с сервера")
 RETURN .F.
ENDIF
CURSORSETPROP ("Tables", m.lcTables, m.tcAlias)
CURSORSETPROP ("KeyFieldList", m.lcKeyFieldList, m.tcAlias)
CURSORSETPROP ("UpdatableFieldList", m.lcUpdatableFieldList, m.tcAlias)
CURSORSETPROP ("UpdateNameList", m.lcUpdateNameList, m.tcAlias)
CURSORSETPROP ("SendUpdates", .T., m.tcAlias)
RETURN .T.
ENDPROC

PROCEDURE Requery_RV
LPARAMETERS tcAlias, tcWhere
IF PCOUNT () > 2 OR ;
  (PCOUNT() > 0 AND VARTYPE (m.tcAlias) # "C") OR ;
  (PCOUNT() = 2 AND VARTYPE (m.tcWhere) # "C")
 ERROR 11
 RETURN .F.
ENDIF
IF PCOUNT() = 0
 IF EMPTY (ALIAS ())
  ERROR 52
  RETURN .F.
 ELSE
  m.tcAlias = ALIAS ()
 ENDIF
ENDIF
IF PCOUNT() < 2
 m.tcWhere = "1 = 1"
ENDIF
IF USED (m.tcAlias)
 DO CASE
 CASE CURSORGETPROP ("SourceType", m.tcAlias) = 1
  * Локальное представление
  LOCAL lcWhere
  m.lcWhere = m.tcWhere
  RETURN REQUERY(m.tcAlias) = 1
 CASE CURSORGETPROP("SourceType", m.tcAlias) = 102
  * Удалённое представление через CA
  PRIVATE pcWhere
  m.pcWhere = m.tcWhere
  RETURN REQUERY(m.tcAlias) = 1
 CASE CURSORGETPROP ("SourceType", m.tcAlias) = 3
  * Таблица
  ERROR 1536
  RETURN .F.
 ENDCASE
ENDIF
LOCAL lcTemplateAlias, lcViewName, lnBuffering
m.lcTemplateAlias = m.tcAlias + "_template"
IF !USED (m.tcAlias) AND !USED (m.lcTemplateAlias)
 ERROR 13, m.tcAlias
 RETURN .F.
ENDIF
IF USED (m.lcTemplateAlias)
 * Есть открытый шаблон
 IF CURSORGETPROP ("SourceType", m.lcTemplateAlias) = 3
  ERROR 1536
  RETURN .F.
 ENDIF
 IF CURSORGETPROP ("SourceType", m.lcTemplateAlias) # 2 OR ;
   EMPTY (CURSORGETPROP ("SourceName", m.lcTemplateAlias))
  ERROR "Неверный шаблон - нужно удалённое представление"
  RETURN .F.
 ENDIF
 * Если проверки прошли, значит имеется "правильный" шаблон
 m.lnBuffering = CURSORGETPROP ("Buffering", m.lcTemplateAlias)
ELSE
 * Не найден открытый шаблон
 IF CURSORGETPROP ("SourceType", m.tcAlias) = 3
  ERROR 1536
  RETURN .F.
 ENDIF
 IF CURSORGETPROP ("SourceType", m.tcAlias) # 2 OR ;
   EMPTY (CURSORGETPROP ("SourceName", m.tcAlias)) OR ;
   EMPTY (CURSORGETPROP ("Database", m.tcAlias))
  ERROR "Неверный шаблон - нужно удалённое представление"
  RETURN .F.
 ENDIF
 * Сделаем "правильный" (в т.ч. по алиасу) шаблон
 m.lcViewName = JUSTSTEM (CURSORGETPROP ("Database", m.tcAlias)) + "!" + ;
   CURSORGETPROP ("SourceName", m.tcAlias)
 USE (m.lcViewName) IN 0 NODATA ALIAS (m.lcTemplateAlias)
 * Закроем "старый" алиас удалённого представления, чтобы он не мешал следующему коду...
 m.lnBuffering = CURSORGETPROP ("Buffering", m.tcAlias)
 USE IN (m.tcAlias)
ENDIF
* Попробуем проверить SPT-курсор
IF USED (m.tcAlias)
 IF CURSORGETPROP ("SourceType", m.tcAlias) = 3
  ERROR 1536
  RETURN .F.
 ENDIF
 IF CURSORGETPROP ("SourceType", m.tcAlias) # 2 OR ;
   !EMPTY (CURSORGETPROP ("SourceName", m.tcAlias))
  ERROR "Неверный SPT-курсор " + m.tcAlias
  RETURN .F.
 ENDIF
 * Теперь можно утверждать что m.tcAlias это SPT-курсор
 IF (CURSORGETPROP ("Buffering", m.tcAlias) = 3 AND ;
   GETFLDSTATE (-1, m.tcAlias) # REPLICATE ("1", FCOUNT (m.tcAlias) + 1)) OR ;
   (CURSORGETPROP ("Buffering", m.tcAlias) = 5 AND ;
   GETNEXTMODIFIED (0, m.tcAlias, .T.) # 0)
  ERROR 1545, m.tcAlias
  RETURN .F.
 ENDIF
ENDIF
* Теперь всё проверено и готово к перезапросу.
LOCAL lcSQL, lnConnHandle, lcTables, ;
 lcKeyFieldList, lcUpdatableFieldList, lcUpdateNameList
* Извлекаем то что есть в RV
m.lcSQL = CURSORGETPROP ("SQL", m.lcTemplateAlias)
m.lnConnHandle = CURSORGETPROP ("ConnectHandle", m.lcTemplateAlias)
m.lcTables = CURSORGETPROP ("Tables", m.lcTemplateAlias)
m.lcKeyFieldList = CURSORGETPROP ("KeyFieldList", m.lcTemplateAlias)
m.lcUpdatableFieldList = CURSORGETPROP ("UpdatableFieldList", m.lcTemplateAlias)
m.lcUpdateNameList = CURSORGETPROP ("UpdateNameList", m.lcTemplateAlias)
SELECT SELECT (m.tcAlias) && Чтобы не вызвать ошибку если нет открытого курсора
USE && Закроем явно
IF " WHERE " $ UPPER (m.lcSQL)
 m.lnRes = SQLEXEC (m.lnConnHandle, ;
  STRTRAN (m.lcSQL, " WHERE " , " WHERE (" + m.tcWhere + ") AND ", ;
  1, 1, 1), m.tcAlias)
ELSE
 m.lnRes = SQLEXEC (m.lnConnHandle, m.lcSQL + " WHERE " + m.tcWhere, m.tcAlias)
ENDIF
IF m.lnRes < 1
 ERROR "Ошибка получения данных с сервера"
 RETURN .F.
ENDIF
CURSORSETPROP ("Tables", m.lcTables, m.tcAlias)
CURSORSETPROP ("KeyFieldList", m.lcKeyFieldList, m.tcAlias)
CURSORSETPROP ("UpdatableFieldList", m.lcUpdatableFieldList, m.tcAlias)
CURSORSETPROP ("UpdateNameList", m.lcUpdateNameList, m.tcAlias)
CURSORSETPROP ("SendUpdates", .T., m.tcAlias)
CURSORSETPROP ("Buffering", m.lnBuffering, m.tcAlias)
CURSORSETPROP ("Buffering", m.lnBuffering, m.lcTemplateAlias)
RETURN .T.
ENDPROC

Как видишь реально работает SPT запрос (прямой запрос), но его курсор делается "обновляемым" - т.е. потом можно пользовать TableUpdate()/TableRevert() Вместо Requery() пользуется соответствующая функция. Use_RV() можно и вообще никогда не пользовать.

У меня на формах в DE ложатся именно RV, только им ставится свойство Nodata - чтоб они данные не тянули. А уж по ходу инициализации формы - где-то там на Init формы или даже позже проводится их перезапрос по Requery_RV("alias", m.lcWhere).

Ессно что в такой схеме проявляется проблема разрушения гридов (реально ведь курсор пересоздаётся а не "перезаполняется") - но как я надеюсь если ты уже дорос до столь серьёзных вопросов, то эта проблема тебя не должна беспокоить :) способы её решения общеизвестны...

Posted via ActualForum NNTP Server 1.0

2 окт 04, 23:28    [1004348]     Ответить | Цитировать Сообщить модератору
 Re: Произвольное предложение WHERE в REMOTE VIEW...  [new]
___DenisKa
Guest
Как говорицца:
автор
"Все гениальное - просто!" ©

Посему я, не мудрствуя лукаво, решил, что я для выборки и отображения данных буду использовать прямые запросы, где построить динамическое предложение WHERE - как "конфетку у ребенка ..." ©, а вот для редактирования конкретного корреспондента (карточки его), будет вызывацца другая форма, специально под ето дело заточенная...
Таким образом я убиваю 2-х зайцев:
1. я получаю гибкую, быструю и удобную для поиска форму для поиска и выбора справочника, где для поиска я собираюсь использовать свой чудо-алгоритм поиска с учетом индекса релевантности, ранее уже описанный мной в форуме по MS SQL (ссылку не приведу - давно дело было...)
2. я получаю гибкую, быструю и удобную для редактирования форму для редактирования.
Ессно внешний вид у них будет координально отличацца, текущий внешний вид и функциональность убога и медленна, как и все универсальное...
Тем не менее, огромное спасибо за ответ - интересное решение!
8 окт 04, 02:03    [1017516]     Ответить | Цитировать Сообщить модератору
Все форумы / FoxPro, Visual FoxPro Ответить