Реферат: MIDAS. Практическое применение
Имя таблицы <Table> берется из Dataset (провайдер великолепно понимает запросы SQL вида Select from...), либо задается в обработчике OnGetTableName. Значения NewValue и OldValue для каждого поля берутся из пакета обновления, посылаемого провайдеру. Имена полей в выражениях SET и FROM формируются автоматически, как раз на основе свойств ProviderFlags и UpdateMode того набора данных, через который провайдер работает с базой. Алгоритм следующий:
В предложение SET входят только те поля, у которых установлен флаг pfUpdate в свойстве ProviderFlags (требуется обновлять в базе данных) и OldValue <> NewValue (значение поля было изменено).
Предложение WHERE формируется следующим образом:
Берутся все поля, у который установлены [pfInKey, pfInWhere], фактически это первичный ключ. При UpdateMode=upWhereKeyOnly больше никаких полей не берется.
При UpdateMode=upWhereChanged к полям первичного ключа добавляются те поля, у которых OldValue <> NewValue и pfWhere in ProviderFlags, что позволяет делать проверку на изменение тех же полей другим пользователем.
При UpdateMode=upWhereAll в список полей WHERE входят все поля записи, у которых pfWhere in ProviderFlags.
В случае, если запись в таблице на сервере не найдена (нет записей, удовлетворяющих условию WHERE), пользователю выдается сообщение вида "Запись изменена другим пользователем", вне зависимости от причины.
Остается одно значение флага, pfHidden. Поля с этим флагом не передаются клиентскому приложению, и не принимаются от него, флаг указывает, что эти поля - только для использования на стороне сервера.
Если уж создан постоянный список полей, можно установить параметры их отображения на клиентской части, в частности, DisplayLabel, DisplayWidth и Visible, а у провайдера - флаги poIncFieldProps. При этом на клиентской части можно не заботиться о списке полей – значения, полученные с сервера приложений, переопределяют заданные на клиенте в любом случае. Заодно у провайдера надо установить опцию poMultiRecordUpdates, чтобы на клиентской части можно было изменять сразу несколько записей в справочнике до отправки изменений на сервер.
Поле CLIENT_ID в справочнике поставщиков и получателей является первичным ключем, а стало быть, в нем должны содержаться уникальные значения. Для получения уникальных значений удобно использовать автоинкрементальные поля (autoincrement field). В IB собственно автоинкрементных полей нет, нарастающие значения получают от генератора с помощью функции Gen_ID, и как правило, присваивают это значение полю в триггере. Мне нравится ситуация, когда новое уникальное значение появляется на клиентской части сразу после добавления записи. Поэтому вместо присвоения значения, полученного от генератора, в триггере, используется хранимая процедура, результатом работы которой и является это значение. Для этого в удаленном модуле данных расположен компонент spNewID: TIBStoredProc, присоединенный к компоненту транзакции ibtDefault, который предоставляет доступ к хранимой процедуре на сервере БД. Процедура описана в базе данных следующим образом:
create procedure CLIENT_ID returns (ID integer) as begin ID = Gen_ID(CLIENT_ID_GEN,1); end |
Как видно, процедура просто выдает следующее значение генератора. Это гарантирует, что при последовательных запросах к ней это значение повторяться не будет. Получение значения на клиентской части обеспечивается методом сервера, об этом немного ниже.
Вторая хранимая процедура, spClientFullName, присоединена к компоненту транзакции ibtClient и предназначена для выдачи имени и телефона поставщика или получателя в виде единой строки «Имя (телефон)», возвращаемой процедурой сервера БД CLIENT_FULL_NAME. Эта строка также передается на клиентскую часть через метод сервера.
Группа компонентов ibtDocList, ibqDocList, dspDocList и ibqDelDoc предназначена для работы со списком документов. У IbtDocList, компонента транзакции, установлен режим read committed, а в компоненте ibqDocList содержится SQL-запрос «select * from List_doc(:FromDate, :ToDate)». Весь список документов сразу выводить довольно бессмысленно, их может быть много. Поэтому запрос выбирает список документов, даты которых лежат в промежутке от FromDate до ToDate. Провайдер dspDocList выдает этот список клиентской части.
Дополнительный компонент, ibqDelDoc, как, думаю, видно из его названия, предназначен для удаления документа, в его свойстве SQL стоит запрос «delete from DOC_TITLE where DOC_ID = :DOC_ID». Несмотря на то, что для создания и изменения документа планируется использовать отдельный модуль, rdmDoc, для удаления документа вовсе необязательно его открывать, и с точки зрения интерфейса пользователя удобно делать это прямо из списка документов. На первый взгляд, использование отдельного запроса для удаления кажется излишним, для этого обычно достаточно объявить в обработчике dspDocList.OnGetTableName имя таблицы (DOC_TITLE), и удаление будет автоматически обеспечено. Однако в постановке задачи стоит условие, что открытый в одной клиентской части документ должен быть недоступен для изменения (а значит, и удаления) из других клиентских частей. Поэтому приходится делать это в обработчике события dspDocList.OnBeforeUpdateRecord следующим образом:
procedure TrdmCommon.dspDocListBeforeUpdateRecord(Sender: TObject; SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind; var Applied: Boolean); var DocID: Integer; begin if UpdateKind = ukDelete then //Толькоеслизаписьудаляется begin DocID := DeltaDS.FieldByName('DOC_ID').AsInteger; К-во Просмотров: 835
Бесплатно скачать Реферат: MIDAS. Практическое применение
|