45803 (MIDAS. Практическое применение), страница 3

2016-07-31СтудИзба

Описание файла

Документ из архива "MIDAS. Практическое применение", который расположен в категории "". Всё это находится в предмете "информатика" из , которые можно найти в файловом архиве . Не смотря на прямую связь этого архива с , его также можно найти и в других разделах. Архив можно найти в разделе "рефераты, доклады и презентации", в предмете "информатика, программирование" в общих файлах.

Онлайн просмотр документа "45803"

Текст 3 страницы из документа "45803"

Теперь все просто: все модули данных, которые работают с документами, используют эти две функции, и если RegisterDoc возвращает false (а это произойдет только в том случае, если номер уже есть в списке), то пользователю выдается сообщение, что с документом уже работают. Функция UnregisterDoc просто удаляет номер из списка.

На клиенте понадобится, кроме доступа к двум провайдерам, еще пара функций – получение нового значения CLIENT_ID для справочника клиентов и получение полного имени клиента. Для этого необходимо создать описание этих функций в библиотеке типов.

В зависимости от того, какой синтаксис используется в редакторе библиотеки типов (IDL или Pascal), объявление этих функций выглядит по-разному, ниже приведены их описания в protected-секции модуля данных:

protected

class procedure UpdateRegistry(Register: Boolean; const ClassID, ProgID: string);

override;

function NewClientID: Integer; safecall;

function Get_ClientName(ClientID: Integer): WideString; safecall;

На IDL это выглядит так:

[id(0x00000001)]

HRESULT _stdcall NewClientID([out, retval] long * Result);

[propget, id(0x00000004)]

HRESULT _stdcall ClientName([in] long ClientID, [out, retval] BSTR * Value);

Реализация этих функций довольно проста. Надо вызвать хранимые процедуры, и выдать возвращаемое ими значение в качестве результата:

function TrdmCommon.NewClientID: Integer;

begin

lock;

with spNewID do

try

ExecProc;

Result := paramByName('ID').AsInteger;

finally

unlock;

end;

end;

function TrdmCommon.Get_ClientName(ClientID: Integer): WideString;

begin

lock;

try

with spClientFullName do

begin

paramByName('ID').AsInteger := ClientID;

ExecProc;

Result := paramByName('FULL_NAME').AsString;

end;

finally

unlock;

end;

end;

Теперь основной модуль готов, и можно перейти к написанию следующего модуля данных, предназначенного для работы с документом.

Рисунок 3.

Здесь уже все немного сложнее. Разумеется, здесь тоже есть соединение с базой ibdDoc, настроенное на сервер БД. Хранимая процедура spNewID выдает на этот раз номер для нового документа, используя процедуру DOC_TITLE_ID, аналогичную процедуре CLIENT_ID.

На этот раз в модуле данных, помимо компонентов запросов к серверу, присутствуют два компонента TСlientDataSet и два провайдера данных. Эти дополнительные компоненты предназначены именно для организации расчетов на сервере. Поскольку, как мы договорились, на сервере приложений должна рассчитываться сумма документа, то на нем должно быть известно содержимое документа до того, как оно будет сохранено в БД. Разумеется, это можно осуществить, используя события провайдера для предварительной обработки пакета изменений, поступившего от клиентской части, но мне хотелось показать возможность организации работы с документом как с полноценным объектом.

Идея простая: пусть весь удаленный модуль данных работает с одним документом. В таком случае этот модуль будет выглядеть для клиентской части как полноценный объект, владеющий всеми данными документа и предоставляющий клиентской части все необходимые свойства. Разумеется, от пакетов данных никто не отказывается.

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

К одному компоненту транзакции ibtDoc присоединено на этот раз два запроса ibqTitle и ibqBody, соответственно выбирающих одну строку заголовка документа (select * from DOC_TITLE where DOC_ID = :DocID) и все строки этого документа (select * from DOC_BODY where DOC_ID = :DocID).

ПРИМЕЧАНИЕ

Хотя MIDAS требует наличия своей IBTransaction для каждой пары компонентов "IBQuery-провайдер", в данном случае это необязательно. Провайдеры не будут начинать и завершать транзакции, открываться и закрываться транзакция будет явно, в соответствующих методах.

К этим запросам присоединены провайдеры dspTitleInner и dspBodyInner, назначение которых – получить данные с сервера БД и передать их в соответствующие ClientDataSet. Свойство Exported у этих провайдеров установлено в false, они нужны только внутри сервера приложений, и видеть их на клиентской части незачем. Соответственно, клиентский набор данных cdsTitle (компонент TClientDataSet) получает одну строку заголовка из dspTitle и cdsBody, содержимое документа из dspBody.

Для того, чтобы клиентская часть могла получать и изменять данные документа, к клиентским наборам данных cdsTitle и cdsBody присоединены провайдеры данных, dspTitle и dspBody, соответственно. Свойству Exported этих провайдеров оставлено значение по умолчанию, True, зато свойство ResolveToDataSet установлено в True, для того, чтобы эти провайдеры не пытались работать с ClientDataSet с помощью запросов. Таким образом, клиентская часть может получать и изменять данные не из TIBQuery, но из TClientDataSet, причем совершенно об этом не догадываясь. По команде с клиентской части изменения, передаются серверу приложений, который и сохраняет их в БД.

Теперь посмотрим, что нам нужно для подобной реализации. Функции для синхронизации обработки документов RegisterDoc и UnregisterDoc уже есть, нужно их только использовать. С их помощью гарантируется, что одновременно один и тот же документ редактироваться не будет, поэтому у провайдеров данных dspTitleInner и dspTitleBody достаточно установить UpdateMode = upWhereKeyOnly, и указать ключевые поля у запросов. Содержимое документа может состоять из нескольких строк, поэтому у dspBodyInner и dspBody нужно установить флаг poAllowMultiRecordUpdates. Теперь нужно разобраться с полями клиентских наборов данных, установив у них соответствующие свойства. Я остановлюсь здесь только на свойстве ProviderFlags. Поскольку поле «Ссылка на документ» (DOC_ID) на клиентской части не нужно, ему можно задать флаг pfHidden. Разумеется, у всех ключевых полей (DOC_ID и LINE_NUM) и в наборе данных заголовка, и в содержимом документа надо указать флаг pfInKey. У провайдеров dspTitle и dspBody нужно установить политику обновления UpdateMode = upWhereKeyOnly, клиентская часть у модуля данных одна, и другие значения совершенно ни к чему.

Теперь компоненты для хранения и обработки данных подготовлены, осталось написать сами методы работы с ними.

Давайте разберемся, что именно требуется. Модуль rdmDoc предназначен как для создания нового документа, так и для редактирования существующего. Этот модуль можен находиться в одном из трех состояний, описанных в перечислении TObjState:

osInactive: данных нет, документ не редактируется,

osInsert: создан новый документ и

osUpdate – происходит изменение существующего документа.

Состояние хранится в переменной Fstate, находящейся внутри модуля. Сразу после создания и после окончания обработки документа модуль данных должен находиться в неактивном состоянии.

Переход из одного состояния в другое должен обеспечиваться соответствующими методами. Я назвал эти методы DoInactiveState (перевод в неактивное состояние), DoOpen (открыть существующий документ) и DoCreateNew (создание нового документа). При редактировании или добавлении документа нужно знать его уникальный номер, записываемый в поле DOC_ID. Для этого достаточно объявить в секции private переменную FDocID: integer, которая и будет его хранить.

В библиотеке типов нужно реализовать методы, которые будут создавать документ или открывать существующий, а также сохранять изменения. Кроме этого, понадобится свойство, позволяющее получить в любой момент сумму по документу. Сумма каждой строки содержимого пусть рассчитывается на клиентской части.

Итак, приступим. Сначала описываются методы перехода между состояниями, они предназначены для внутреннего использования, и поэтому их объявления содержатся в секции private:

procedure DoInactiveState;

procedure DoCreateNew;

procedure DoOpen(DocID: integer);

Рассмотрим их по порядку.

procedure TrdmDoc.DoInactiveState;

begin

UnregisterDoc(FDocID);

FDocID := 0;

cdsTitle.Active := False;

cdsBody.Active := False;

ibtDoc.Active := False;

FState := osInactive;

end;

Процедура DoInactiveState удаляет документ из списка редактируемых, закрывает все клиентские наборы данных, а также производит откат транзакции (если она была активна).

procedure TrdmDoc.DoOpen(DocID: Integer);

begin

if DocID = 0 then Exit;

try

if not RegisterDoc(DocID) then

raise Exception.Create('Документ редактируется');

FDocID := DocID; // и только здесь, иначе DoInactiveState удалит документ

ibdDocs.Connected := True;

ibtDoc.StartTransaction;

with cdsTitle do

begin

params.paramByName('DocID').AsInteger := FDocID;

Active := True;

if BOF and EOF then

raise Exception.Create('Документ не найден');

end;

with cdsBody do

begin

params.paramByName('DocID').AsInteger := FDocID;

Active := True;

end;

FState := osUpdate;

ibtDoc.Commit;

except

DoInactiveState;

raise;

end;

end;

DoOpen предназначена для открытия существующего документа, идентификатор DOC_ID которого равен входному параметру DocID. Первым делом с помощью RegisterDoc производится проверка того, что документ в данный момент не редактируется. Затем идентификатор документа запоминается, и в клиентские наборы данных загружаются данные документа. В случае ошибки состояние документа переводится в osInactive.

procedure TrdmDoc.DoCreateNew;

var

NewDocID: Integer;

begin

try

NewDocID := NewID;

if not RegisterDoc(NewDocID) then

raise Exception.Create('Документ редактируется');

FDocID := NewDocID;

ibdDocs.Connected := True;

ibtDoc.StartTransaction;

with cdsTitle do

begin

params.paramByName('DocID').AsInteger := FDocID;

Active := True;

Append;

Post;

end;

with cdsBody do

begin

params.paramByName('DocID').AsInteger := FDocID;

Active := True;

end;

ibtDoc.Commit;

FState := osInsert;

except

DoInactiveState;

raise;

end;

end;

Процедура DoCreateNew предназначена для создания нового документа. Она практически аналогична предыдущей, за исключением того, что идентификатор документа получается от сервера БД с помощью процедуры NewID, которая обращается к хранимой процедуре на сервере. Реализация процедуры DoCreateNew очень похожа на аналогичную реализацию в rdmCommon.

Для того, чтобы вставка новой записи в документ происходила верно, достаточно написать обработчик cdsTitle.OnNewRecord, задающий начальное значение полей записи, и практически такой же обработчик для cdsBody:

procedure TrdmDoc.cdsTitleNewRecord(DataSet: TDataSet);

var

Day, Month, Year: Word;

begin

DecodeDate(Date, Year, Month, Day);

with cdsTitle do

begin

FieldByName('DOC_ID').AsInteger := FDocID;

FieldByName('DOC_NUM').AsString := IntToStr(FDocID)

+ '/' + IntToStr(Year);

FieldByName('DOC_DATE').asDateTime := Date;

FieldByName('DOC_SUM').asCurrency := 0;

FieldByName('FROM_ID').AsInteger := 0;

FieldByName('TO_ID').AsInteger := 0;

end;

end;

procedure TrdmDoc.cdsBodyNewRecord(DataSet: TDataSet);

begin

cdsBody.FieldByName('DOC_ID').AsInteger := FDocID;

end;

В дополнение ко всему нужна еще одна процедура в секции private, для подсчета суммы документа:

function TrdmDoc.CalcSum: Currency;

begin

Result := 0;

if not cdsBody.Active then Exit;

with cdsBody do

begin

First;

while not EOF do

begin

Result := Result

+ FieldByName('COUNT_NUM').asCurrency

* FieldByName('PRICE').asCurrency;

Next;

end;

end;

end;

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

Теперь надо позаботиться о клиентской части, то есть создать необходимые внешние методы сервера в библиотеке типов. Описание этих методов, созданное редактором библиотек типов, выглядит следующим образом:

protected

function ApplyChanges: WideString; safecall;

function Get_DocID: Integer; safecall;

procedure CreateNewDoc; safecall;

procedure Set_DocID(Value: Integer); safecall;

function Get_DocSum: Currency; safecall;

Функциональность этих методов такова:

Свежие статьи
Популярно сейчас
Почему делать на заказ в разы дороже, чем купить готовую учебную работу на СтудИзбе? Наши учебные работы продаются каждый год, тогда как большинство заказов выполняются с нуля. Найдите подходящий учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
5184
Авторов
на СтудИзбе
436
Средний доход
с одного платного файла
Обучение Подробнее