3.4.2 Использование запросов при обращении к базе данных

            При работе с базой данных, находящейся на удаленном сервере, выборка необходимых данных из базы может быть сделана с помощью SQL-запроса. Для его реализации разработан ряд технологий, среди которых наиболее простой является технология Web брокер. Рассмотрим ее реализацию на простом примере. Брокер Web состоит из различных мастеров и компонентов, упрощающих создание серверов Web типов CGI, ISAPI и NSAPI. Сервера этих типов предоставляют очень простой и несложный в использовании способ создания распределенных приложений, работа пользователя с которыми производится посредством Web-браузера.
          В С++Builder создаем новый проект с использованием траектории File->New->Other->Web Server Application. При этом на форме появится WebModule1. На него переносим компоненты DataSetPageProducer, Query, DataSource. Назовем компонент Query как CountryQuery. В компоненте DataSource установим свойство DataSet в CountryQuery. В CountryQuery укажем имя базы данных BCDEMOS. В DataSetPageProducer в свойство HTMLDOC введем следующий текст
<HTML>
<BODY>

<B>Country:</B> <#Name><BR>
<B>Continent:</B> <#Continent><BR>
<B>Captial:</B> <#Capital><BR>
<B>Area:</B> <#Area><BR>
<B>Population:</B> <#Population><BR>
<HR>

<FORM ACTION="/DataSetProduce.exe" METHOD=POST>
<P>Enter the name of a country in North or South America.
(Mexico also supported.)</P>
<INPUT TYPE=EDIT NAME=EDIT1>
<INPUT TYPE=SUBMIT NAME=NAVIGATOR VALUE="Navigate">
</BODY>
</HTML>
Создадим действие по умолчанию и опишем обработчик события этого действия в виде
void __fastcall TWebModule1::WebModule1WebActionItem1Action(
TObject *Sender, TWebRequest *Request, TWebResponse *Response,
bool &Handled)
{
if (Request->ContentFields->Count > 0)
{
AnsiString S = Request->ContentFields->Values["Navigator"];
if (S == "Navigate")
{
S = Request->ContentFields->Values["EDIT1"];
char SQL[250];
sprintf(SQL, "Select * from Country where Name like \"%s\"", S.c_str());
CountryQuery->Close();
CountryQuery->SQL->Clear();
CountryQuery->SQL->Add(AnsiString(SQL));
CountryQuery->Open();
}
}
Response->Content = DataSetPageProducer1->Content();}

         Не забудем подключить библиотеку <stdio.h> в модуль Unit1.cpp, чтобы объявить функцию sprintf. Транслируем программу и записываем ее в виде DataSetProduce.exe файла в каталог wwwroot. После этого вызываем ее из браузера по ссылке http://user3/ DataSetProduce.exe (Рисунок 6).

Рисунок 6. Пример использования Producer при обработке запроса

              Сделаем некоторые пояснения к программе. Тег <#Name> в тексте HTML <B>Country:</B><#Name><BR> заменяется обработчиком события OnAction в компоненте TDataSetPageProducer текущим значением поля Name из записи. Таким образом, необходимо создавать теги, имеющие то же самое имя, что и поля таблицы.
В форме созданы теги для каждого поля таблицы Country. В нижней части форма позволяет пользователю ввести наименование страны. Как только пользователь нажимает кнопку на форме, программа делает попытку отобразить данные о стране, наименование которой было введено. В программе нет обработки ошибок на случай, если введено неправильное наименование страны. В тексте обработчика OnAction используется свойство ContentFields для проверки того, щелчок по какой кнопка обрабатывается. Использование этого свойства позволяет написать код, отличающий кнопки формы одну от другой. Это может быть полезно в случае, если Вы создаете формы, имеющие несколько кнопок на ней, например, OK, Cancel и Abort.
Полагая, что пользователь щелкнул по кнопке Navigate, приведенная программа получает строку, введенную пользователем. Эта строка используется для построения правильного утверждения SQL вида Select * from X where Y = Z. Данная программа закрывает таблицу и открывает ее с новым утверждением SQL. Все, что теперь остается - вернуть значения нового утверждения SQL.
Если выполненное утверждение SQL возвращает несколько строк, то будет показана только первая из них. Если не найдено ни одной строки, то показывается форма, в которой нет никаких данных.
В следующем примере рассмотрим, как создаются программы, позволяющие отобразить сразу несколько строк данных, полученных через Интернет. Имя сервера, который мы создадим, будет OneToMany.exe.
Как только пользователь первый раз обращается к программе, он видит список наименований компаний, показанный на рисунке 7

Рисунок 7. Запрос из базы данных по определенной компании

             Если он щелкает по одному из этих наименований, то появляются детали сделок, совершенных компанией, которые хранятся во второй таблице, как показано на рисунке. Сделки хранятся во второй таблице, связанной с первой отношением главный/подчиненный (master/detail).

Рисунок 8. Ответ удаленной базы данных на запрос клиента

              На рисунке 8 видно, что компания номер 1384 имеет десять сделок. Вы можете видеть даты сделок. Чтобы начать построение этой программы, установите на форму TTable и TQuery. Назовите TTable CustomerTable, а TQuery OrdersQuery. Установите связь таблицы с таблицой Customer базы данных BCDEMOS. Установите параметры запроса так, чтобы он был связан с таблицей Orders базы данных BCDEMOS, а собственно запрос выглядел бы так: Select * from Orders where CustNo = :CustNo.
Перенесите поля записи с помощью редактора полей и установите ширину бордюра равную 1.
             Чтобы проверить сделанное, откройте запрос OrdersQuery и заполните его свойство Params так, чтобы тип данных (DataType) был ftInteger и тип параметра (ParamType) был бы ptInput. Теперь можно изменить состояние запроса на Active, подтвердив тем самым, что утверждение SQL записано верно.
Чтобы начать работу с CustomerTable, установите на Ваш модуль Web TPageProducer и назовите его CustomerProducer. Добавьте следующий код к свойству HTMLDoc продюсера страницы (page producer):
<HTML>
<HEAD>
<TITLE>Companies</TITLE>
</HEAD>
<BODY>
<H2>Company</H2>
<HR>
Click highlight words to view Company Info.<P>
<#CompanyType><P>
</BODY>
</HTML>

          Как видно, в этом примере имеется тег, названный <#CompanyType>. Для его обработки надо добавить действие WebActionItem к модулю Web, выглядящее так:
Response->Content=CustomerProducer->Content();
Собственно работа по занесению информации о теге обычно производится не в действии ActionItem, а в обработчике события OnHTMLTag используемого в настоящий момент продюсера, в нашем случае это CustomerProducer. Вот приемлемый для этой цели его код:
void __fastcall TWebModule1::CustomerProducerHTMLTag(TObject *Sender,
TTag Tag, const AnsiString TagString, TStrings *TagParams,
AnsiString &ReplaceText)
{
AnsiString S, Temp, CustNo, FormatString;

CustomerTable->Open();
CustomerTable->First();
while (!CustomerTable->Eof)
{
Temp = CustomerTable->FieldByName("Company")->AsString;
CustNo = CustomerTable->FieldByName("CustNo")->AsString;
FormatString =
"<a href=http://user3/OneToMany.exe/orders?CustNo=%s>%s</a><BR>";
S = S + Format(FormatString, OPENARRAY(TVarRec, (CustNo, Temp)));
CustomerTable->Next();
}
CustomerTable->Close();
ReplaceText = S;
}
                   Этот метод выбирает поля Company и CustNo из каждой записи таблицы Customer и вставляет их последовательно в ссылки, выглядящие примерно так:
<a href=”/OneToMany.exe/Orders?CustNo=1221”>Kauai Dive Shoppe</a>
Если пользователь щелкает по первой ссылке, то сервер вызывается со следующим URL:
http://user3/OneToMany.exe/Orders?CustNo=1334
Как Вы можете видеть, сервер вызывается с URI (PathInfo), равным /Orders. Вам, следовательно, необходимо создать новое действие WebActionItem, содержащее /Orders в своем PathInfo.
Запрос, передаваемый обработчику события OnAction, выглядит примерно так: CustNo=1334. Из того, что Вы прочитали ранее, Вы можете подумать, что было бы можно использовать свойство QueryFields объекта Request для разбора этой информации. А затем использовать полученные данные для формирования утверждения SQL, возвращающего затребованные пользователем данные. В самом деле, если есть желание, Вы можете пойти таким путем. Однако, так случилось, что VCL имеет компонент, называемый TQueryTableProducer, который сам разберет запрос для Вас, и автоматически сформирует реквизиты SQL, чтобы выбрать правильные строки из таблицы Orders.
          Для осуществления всей этой работы, сначала необходимо сбросить на TWebModule TQueryTableProducer. Установите его свойство Query как OrdersQuery. Теперь заполните свойство PathInfo действия WebActionItem значением /Orders. В результате должно получиться:
Response->Content=QueryTableProducer1->Content();
             Теперь, как только вызывается сервер с помощью следущего URL, автоматически получаются корректные данные из подчиненной таблицы, как это показано на рисунке:
/OneToMany.exe/Orders?CustNo=1334
            Что здесь важно, так это то, что построен запрос Query, называемый CustNo, в котором установлен правильный номер компании (customer number). В запросе должен быть указан правильный номер (т.е. CustNo), иначе он не будет работать. Можно собирать вместе несколько полей для построения более сложных запросов, используя синтаксис с символом &. Следующий пример показывает, как передаются несколько полей в случае сложного запроса со многими параметрами:
/OneToMany.exe/Orders?CustNo=1231&LastName=”Smith”&FirstName=”Paul”
             Если запрос имеет параметры CustNo, FirstName и LastName, то приведенный URL будет соответствовать ему.
              В заключении следует указать, что приведенное выше отнюдь не исчерпывает возможности современных языков программирования и вне этого изложения остались многие вопросы, ответы на которые вам придется искать в указанных ниже учебниках и на необъятных просторах Интернета.С уважением к будущим читателям- автор.