На прошлой лекции мы рассматривали создание сервера приложений на основе удаленного модуля данных Remote Data Module. Эта лекция посвящена созданию клиентской части многоуровневых приложений на основе технологии . Связать клиентское приложение с одной таблицей очень просто. Связать две или более таблицы в отношении один-ко-многим несколько сложней, тут есть свои тонкости. Именно такую связь мы и будем делать. Кроме того, мы разберем способ реализации отложенной обработки, когда данные можно сохранить в файл, и при необходимости, загрузить их из файла без соединения с удаленным сервером приложений.
Связь клиентского приложения с удаленным модулем данных организуется одним из компонентов связи, расположенных на вкладке
Разберем новый материал на практике, попутно останавливаясь на важных моментах.
Начните новый проект. В свойстве Name главной формы напишите fMain, в свойстве Caption напишите "Клиент удаленного сервера", сохраните ее модуль под именем Main, а проект в целом - MyNewClient. На форму поместите три простых панели, сразу же очистив их свойство Caption. У верхней панели в свойстве Align выберите alTop, а в свойстве AutoSize установите True. Поместите на эту панель навигатор DBNavigator с вкладки
У нижней панели в свойстве Align выберите alBottom, чтобы она заняла всю нижнюю часть формы. На панель поместите сетку DBGrid и шесть простых кнопок.
Средняя панель в свойстве Align будет иметь значение alClient. На ней помещается только одна сетка DBGrid, которая в свойстве Align также имеет значение alClient. Внешний вид формы представлен на рисунке ниже:
(рис 29.1 ) Главная форма клиентского приложенияСвойство Name у кнопок переименуйте, соответственно, в:
bConnectbRefreshbSaveToDBbUnConnectbSaveToFilebLoadFromFileСвойство Caption кнопок измените, как на рисунке.
Верхнюю сетку и навигатор позже соединим с главной таблицей LichData, нижняя сетка отобразит данные .
Для невизуальных компонентов доступа создадим обычный модуль данных. Выберите команду File -> New -> Data Module. В свойстве Name модуля данных укажите , а сам модуль сохраните на диск под именем DM. Не забудьте в главной форме командой File -> Use Unit подключить этот модуль.
Перейдем на вкладку . Вы видите целый ряд компонентов, реализующих подключение с удаленным модулем данных различными технологиями. Нам нужен компонент , поместите его в модуль данных. Для краткости обращений к компоненту переименуйте его свойство Name в DCOMC. Теперь нужно подключить его к удаленному серверу. В свойстве IP -адрес компьютера, на котором расположен сервер приложений. Поскольку у нас все хранится на одном компьютере, укажем адрес 127.0.0.1, то есть, локальный IP -адрес.
Теперь щелкнем по выпадающему свойству
MyNewServer.MyRDM
Выберем эту строку. В свойстве Windows автоматически загрузит сервер приложений, который мы делали на прошлой лекции. Вот таким простым способом клиентское приложение связывается с удаленным модулем данных. Как видите, компонент содержит минимум необходимых свойств.
Теперь нам нужно подключиться к наборам данных на сервере. Для этого используется компонент
Компонент
Компонент
Рассмотрим основные свойства и методы компонента
| Свойство | Описание |
|---|---|
| ChangeCount | Содержит количество изменений в буфере. После явного сохранения изменений в базу данных, это свойство содержит 0. |
| CommandText | Содержит текст SQL -запроса, который может быть выполнен методом Execute компонента. Таким образом, можно изменять НД, предоставляемый сервером. |
| Data | Свойство содержит пакет данных, предназначенный для передачи по сети в специальном транспортном формате. |
| DataSize | Размер в байтах пакета Data. |
| При отношении один-ко-многим, свойство у подчиненного |
|
| Delta | Пакет с измененными данными, которые еще не сохранены на сервере. |
| FetchOnDemand | При значении True (по умолчанию) разрешает компоненту получать очередной пакет данных по мере надобности, например при прокрутке сетки . |
| FileName | Может содержать имя файла, в которое при необходимости будет сохранять данные, или считывать их. Если этого имени нет, можно использовать SaveDialog или OpenDialog для получения этого имени от пользователя. |
| PacketRecords | Указывает количество записей, получаемых из серверного НД в одном пакете. По умолчанию равно -1, то есть считываются все записи. Если значение равно 0, то считываются только метаданные. |
| ProviderName | Имя компонента-провайдера на стороне сервера ( ), который предоставляет доступ к нужному набору данных. |
| RemoteServer | Имя компонента соединения (например, |
Теперь рассмотрим основные методы компонента
| Метод | Описание |
|---|---|
| AddIndex | Создает локальный индекс. |
| ApplyRange | Включает механизм фильтрации по созданному ранее диапазону. |
| Обновляет записи в базе данных. Имеет параметр - максимальное количество ошибок (по умолчанию 0), после которых обновление прекращается. Возвращает целое число - количество действительно допущенных ошибок. | |
| Cancel | Отменяет все неподтвержденные |
| CancelRange | Отменяет механизм фильтрации по указанному диапазону. |
| CancelUpdates | Отменяет все неподтвержденные изменения из пакета Delta, предназначенные для дальнейшей передачи на сервер. |
| DeleteIndex | Удаляет локальный индекс. |
| EmptyDataSet | Очищает буфер от всех записей. |
| Execute | Выполняет SQL -запрос из свойства CommandText, меняя НД на стороне сервера. |
| FetchBlobs | По умолчанию, большие BLOB -столбцы, которые могут содержать изображение, музыку или какие либо двоичные данные, в целях разгрузки трафика клиенту не передаются. Метод FetchBlobs явно запрашивает с сервера содержимое текущего BLOB -столбца. |
| FetchDetails | Запрашивает с сервера недостающие данные из вложенных или FetchOnDemand имеет значение True, то эти данные подгружаются автоматически, и применять метод не нужно. |
| FetchParams | Получает с сервера приложений текущие параметры набора данных провайдера. Если параметров нет, метод не делает ничего. |
| GetNextPacket | Запрашивает с сервера очередной пакет записей, который будет добавлен к свойству Data. Длина пакета в записях определяется свойством PacketRecords. |
| LoadFromFile | Загружает данные из локального файла. Вместе с SaveToFile позволяет организовать отложенную обработку данных. Подробнее об этом поговорим ниже. |
| LoadFromStream | Загружает данные из потока. |
| Post | Подтверждает сделанные изменения в буфере. На сервере данные при этом не меняются, для этого нужно явно вызвать метод |
| RefreshRecord | Обновляет текущую запись, запрашивая ее с сервера. |
| RevertRecord | Восстанавливает текущую запись, если она была изменена, но еще не сохранена на сервере. |
| SaveToFile | Сохраняет данные в локальный файл. Отличается от аналогичного метода других компонентов наличием второго параметра - формата данных файла. Может быть три формата: dfBinary - двоичный формат, dfXML - формат XML и dfXMLUTF8 - формат XML в кодировке UTF8. |
| SaveToStream | Сохраняет данные в поток. |
Вернемся к нашему проекту. Поместите в модуль данных два компонента DCOMC. Далее в свойстве ProviderName следует выбрать нужного провайдера, который обеспечит связь с НД сервера. Для первого DSPLichData, для второго - DSPTelephones. Соответственно, у первого компонента CDSLichData, у второго - CDSTelephones.
Для того, чтобы связать навигатор DBNavigator и сетки DBGrid на главной форме, нам потребуются два компонента DataSource с вкладки . Первый назовите dsLichData и в свойстве DataSet свяжите его с набором данных CDSLichData, второй назовите dsTelephones и свяжите его с CDSTelephones. Откройте оба
Вернитесь на главную форму. Навигатор и верхнюю сетку через свойство DataSource подключите к , нижнюю сетку подключите к . Сетки при этом должны отобразить данные. Сохраните проект, скомпилируйте и загрузите. Сразу же при этом проявляется ошибка: нижняя сетка содержит подчиненные данные из таблицы , относящиеся к первой записи главной таблицы LichData. При смене записи в главной таблице, подчиненная таблица записей не меняет, несмотря на то, что мы организовали связь один-ко-многим на стороне сервера. Обусловлено это тем, что при начале работы подчиненная таблица получила нужные записи в локальный буфер, и теперь с ними работает, не изменяя его. Точно также, если мы сейчас попробуем сохранить данные таблиц в локальный файл, то записи главной таблицы сохранятся полностью, подчиненная же таблица сохранит лишь те записи, которые есть в кэше. Исправим эту ситуацию.
Вернитесь в модуль данных. Щелкните дважды по компоненту CDSLichData, который содержит данные главной таблицы. Откроется LichData редактор отобразил еще одно поле: TTelephones, которое имеет тип OK закройте
Перейдем к подчиненному компоненту CDSTelephones. В свойстве CDSLichDataTTelephones. При этом автоматически очистятся свойства RemoteServer и ProviderName. Теперь этот НД связан с сервером через главную таблицу, а не напрямую. Снова сохраните проект, скомпилируйте и загрузите его. Теперь
Однако это не все. На модуль данных установите также два диалога: SaveDialog и OpenDialog. Переименуйте их соответственно, в SD1 и OD1. Выделите оба диалога и откройте редактор свойства Filter. В редакторе укажите единственную строчку:
Файлы данных | *.dat
В свойстве DefaultExt диалогов укажите расширение по умолчанию, "dat" (разумеется, без кавычек). В свойстве FileName укажите имя файла по умолчанию: "LichData.dat". В свойстве InitialDir укажите папку по умолчанию: "C:\". Таким образом, мы настроили оба диалога на работу с файлом
C:\LichData.dat
Конечно, пользователь сможет изменить и адрес, и имя файла, но по умолчанию будут использованы наши настройки. Осталось изменить свойство Title диалогов. У OD1 укажите "Открыть файл с личными данными", у SD1 - "Сохранить файл с личными данными".
Вернемся к главной форме. Создайте обработчик нажатия на кнопку "Подключиться к базе". Код обработчика приведен ниже:
procedure TfMain.bConnectClick(Sender: TObject);
begin
//если нет подключения:
if not fDM.DCOMC.Connected then begin
// подключаем DCOMConnected
fDM.DCOMC.Connected:= True;
//открываем наборы данных:
fDM.CDSLichData.Open;
fDM.CDSTelephones.Open;
end; //if
end;
Комментарии достаточно подробны, чтобы вы смогли разобраться с кодом. Обработчик нажатия на "Обновить данные" будет таким:
procedure TfMain.bRefreshClick(Sender: TObject); begin //отменяем все неподтвержденные изменения: fDM.CDSLichData.CancelUpdates; fDM.CDSTelephones.CancelUpdates; end;
При отмене неподтвержденных изменений с сервера считывается текущий набор данных, и сетки будут отображать действительное положение дел. Кнопка "Сохранить изменения в базу" вызовет следующий обработчик:
procedure TfMain.bSaveToDBClick(Sender: TObject);
var i,k: Integer; //для подсчета ошибок
begin
i:= fDM.CDSLichData.ApplyUpdates(0);
k:= fDM.CDSTelephones.ApplyUpdates(0);
if i + k > 0 then
ShowMessage('При сохранении данных выявлено ошибок: '+
IntToStr(i+k))
else ShowMessage('Данные сохранены');
end;
Переменные целого типа нам нужны для подсчета возможных ошибок при сохранении данных на сервер. Метод i и k окажется больше 0, ошибки были допущены. Иначе ошибок не было.
Код кнопки "Отключиться от базы" будет таким:
procedure TfMain.bUnConnectClick(Sender: TObject); begin //отключаем таблицы fDM.CDSLichData.Close; fDM.CDSTelephones.Close; //отключаем DCOMConnection fDM.DCOMC.Close; end;
Вначале мы закрываем наборы данных, после чего прерываем подключение к серверу. Теперь сохраните проект, скомпилируйте его и загрузите. Попробуйте отредактировать какую-нибудь запись. Затем нажмите "Обновить данные", либо последовательно, отключитесь от сервера и снова подключитесь к нему. Вы убедитесь, что сделанные изменения не сохранились. Это подтверждает, что при редактировании мы изменяем данные в кэше, а вовсе не на сервере. Если вы снова измените запись, затем нажмете "Сохранить изменения в базу", то изменения передадутся на сервер. Повторное обновление данных убедит вас в этом.
Теперь нам осталось написать обработчики для кнопок "Сохранить данные в файл" и "Загрузить данные из файла". Однако здесь следует сделать одно замечание. Как уже говорилось, метод SaveToFile () компонента DBClient. Этот модуль уже подключен к нашему модулю данных DM, однако он не подключен к главной форме. Следовательно, в главной форме мы не сможем реализовать сохранение данных в файл и чтение их из файла, если не подключим этот модуль в раздел uses. Чтобы дважды не подключать его к проекту, реализуем методы сохранения в файл и чтения из файла в модуле данных, а в главной форме просто вызовем их.
Перейдите к модулю данных. В разделе Public опишите две процедуры:
public
{ Public declarations }
procedure SaveDataToFiles;
procedure LoadDataFromFiles;
Установите курсор на одну из них и нажмите <Ctrl+Shift+C>, чтобы сгенерировать обе эти процедуры. Эти процедуры будут такими:
{Читаем данные из файла}
procedure TfDM.LoadDataFromFiles;
begin
if OD1.Execute then begin
CDSLichData.LoadFromFile(OD1.FileName);
ShowMessage('Процедура чтения данных выполнена!');
end; //if
end;
//**************************************
{Сохраняем данные в файл}
procedure TfDM.SaveDataToFiles;
begin
if SD1.Execute then begin
CDSLichData.SaveToFile(SD1.FileName, dfBinary);
ShowMessage('Процедура сохранения данных выполнена!');
end; //if
end;
Комментарии достаточно подробны и не нуждаются в дополнительных пояснениях. Код кнопки "Сохранить данные в файл" на главной форме просто вызывает нужную процедуру:
procedure TfMain.bSaveToFileClick(Sender: TObject); begin fDM.SaveDataToFiles; end;
А код кнопки "Загрузить данные из файла" будет следующим:
procedure TfMain.bLoadFromFileClick(Sender: TObject); begin fDM.LoadDataFromFiles; end;
Сохраните проект, скомпилируйте и загрузите его. Соединитесь с базой данных, чтобы считать данные. Сохраните их в файл и отключитесь от базы данных. Считайте данные из локального файла, не подключаясь к БД. Вы видите, что сохранились данные не только главной, но и TTelephones, каждая запись главной таблицы содержит также связанные данные из
На этом наш курс "Программирование баз данных в Delphi " окончен. Желаю всевозможных успехов в программировании!
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.