Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ЛБ(ПРИС)_Файл-сервер_2016.doc
Скачиваний:
5
Добавлен:
17.06.2023
Размер:
5.49 Mб
Скачать
  1. Организация многопользовательского режима

Многопользовательский режим выражается в недоступности удаления (или редактирования) записи одним пользователем, если эта запись уже используется другим пользователем, а также своевременное обновление набора данных по таймеру или по желанию пользователя. Период обновления задаётся в соответствии со здравым смыслом. Наиболее часто используемые справочники следует обновлять наиболее часто, редко используемые – реже.

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

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

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

  • checkEdit - проверка признака редактирования;

  • isEdit - установка признака редактирования;

  • notEdit - снятие признака редактирования;

Для проверки редактирования добавим в модуль данных новую пару компонентов ADOQuery и DataSource. Переименуем компонент ADOQuery в CheckEditQuery, таким образом, модуль данных будет иметь вид показанный на рисунке 39.

Рисунок 39 – Модуль данных

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

Свяжем DataSource2 с CheckEditQuery и ADOConnection1.

Добавим на форму компонент DBEdit. Укажем в его свойстве DataSource значение DM.DataSource2.

Ниже в таблице 4 приведены события компонентов и применяемые в них процедуры.

Таблица 4 – События компонентов и применяемые процедуры

Компонент

Событие

Процедура

DBEdit1, DBEdit2, DBEdit3, DBLookupComboBox1, DBLookupComboBox2, DateTimePicker1

onEnter

checkEdit

isEdit

DBEdit1, DBEdit2, DBEdit3, DBLookupComboBox1, DBLookupComboBox2, DateTimePicker1

onExit

notEdit

MainForm

onClose

notEdit

DBEdit0

onChange

checkEdit

Код процедур приведён ниже:

procedure TS_sotrudnikiForm.isEdit;

begin

if DBEdit0.Text<>'' then

begin

DM.CheckEditQuery.SQL.Text:='UPDATE SOTR SET SOTR.EDIT = True WHERE SOTR.S_ID='+DBEdit0.Text+';';

DM.CheckEditQuery.ExecSQL;

DM.CheckEditQuery.SQL.Text:='select * from SOTR WHERE S_ID='+DBEdit0.Text+';';

DM.CheckEditQuery.Open;

end;

procedure TS_sotrudnikiForm.notEdit;

begin

if DBEdit0.Text<>'' then

begin

DM.CheckEditQuery.SQL.Text:='UPDATE SOTR SET SOTR.EDIT = False WHERE SOTR.S_ID='+DBEdit0.Text+';';

DM.CheckEditQuery.ExecSQL;

DM.CheckEditQuery.SQL.Text:='SELECT * FROM SOTR WHERE S_ID='+DBEdit0.Text+';';

DM.CheckEditQuery.Open;

end;

end;

function TS_sotrudnikiForm.checkEdit:boolean;

var bool:boolean;

begin

checkEdit:=false;

if DBEdit0.Text<>'' then DM.CheckEditQuery.SQL.Text:='select * from SOTR WHERE S_ID='+DBEdit0.Text+';';

DM.CheckEditQuery.Open;

if DBEdit5.Text<>'' then

begin

bool:=not strtobool(DBEdit5.Text);

DBEdit1.Enabled:=bool;

DBEdit2.Enabled:=bool;

DBEdit3.Enabled:=bool;

DateTimePicker1.Enabled:=bool;

DBLookupComboBox1.Enabled:=bool;

DBLookupComboBox2.Enabled:=bool;

Label10.Visible:= not bool;

checkEdit:=not bool;

end;

end;

Результат работы представлены на рисунке 40.

Рисунок 40 – Организация многопользовательского режима

Далее рассмотрим обновление. По желанию пользователя обновление осуществляется нажатием по кнопке обновить на DBNavigator . Если есть желание можно сделать отдельно кнопку «Обновить». (см. ПРИМЕР программы)!!!

Для автоматического обновления следует добавить компонент Timer с вкладки System (не забудьте подключить модуль ExtCtrls, включающий класс TTimer). Данный компонент имеет единственное событие – срабатывание таймера. То есть если поставить в свойстве Interval значение 1000 (1000мс=1с) то каждую секунду будет срабатывать событие OnTimer.

Итак, в свойстве Interval компонента Timer установим значение 30000 (30с). То есть через каждые 30 секунд таймер будет срабатывать и данные будут обновляться.

В событии OnTimer, компонента Timer следует вставить следующий код:

procedure TS_sotrudnikiForm.Timer1Timer(Sender: TObject);

begin

// как-бы нажимаем на кнопку обновить по наступлении события от таймера

// если запись не редактируется

if DBNavigator1.Controls[6].Enabled then

begin

DBNavigator1.BtnClick(nbEdit);

DBNavigator1.BtnClick(nbRefresh);

end;

end;

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

1). При нажатии на кнопку навигатора Refresh, осуществляется проверка признака редактирования и обновление данных (данный метод был реализован для справочника «Хобби» см. пример процедуры BeforeAction для формы «Хобби» на стр. 20).

Примечание: Недостатком данного метода является то, что если несколько пользователей одновременно работают с одним и тем же справочником, то добавление записи одним из пользователей будет заметно другим лишь после закрытия и открытия формы. А при удалении записи будет появляться сообщение, информирующее об удали. Кроме того в данном случае нельзя обновление данных проводить вручную при нажатии на кнопку «Обновить» навигатора, так как при нажатии происходит только проверка признака редактирования, ссылки на процедуру обновления Refresh нет.

2). Можно вставить ссылку на процедуру Refresh. При этом необходимо реализовывать возвращение курсора обратно на запись до обновления. (Это можно сделать, запомнив в глобальной переменной номер текущей записи перед обновлением, затем закрыть и выполнить запрос заново и, наконец, с помощью метода Locate для набора данных переставить курсор по запомненному номеру). Данный способ является более полным, так как позволяет устранить недостатки, характерные для первого способа.

Пример процедуры BeforeAction для формы «Сотрудники»:

procedure TS_sotrudnikiForm.DBNavigator1BeforeAction(Sender: TObject;

Button: TNavigateBtn);

var n:integer;

begin

ins:=false;

// Если нажата кнопка "Вставить", тогда

// передаём фокус в DBEdit1, если он доступен

if Button=nbInsert then

begin

ins:=true;

if DBEdit1.Enabled then DBEdit1.SetFocus;

Image1.Picture:=nil;

end;

// Если нажата кнопка «Обновить»

if (Button=nbRefresh) then

begin

// Присваиваем переменной n номер текущей записи

n:=DBEdit1.DataSource.DataSet.FieldValues['S_ID'];

// Вызываем процедуру «обновить»

Refresh;

// Возвращаем курсор на прежнюю запись

dm.SotrQuery.Locate('S_ID', n, []);

end;

// Передаём дату в DBEdit4

DBEdit4.EditText:=datetostr(DateTimePicker1.Date);

// Если нажата кнопка «Принять», тогда передаём фокус в DBGrid1

if Button=nbPost then DBGrid1.SetFocus;

// Если не активна 1я кнопка, тогда выставляем признак редактирования

if not DBNavigator1.Controls[1].Enabled then isEdit;

// Не забываем удалять файл изображения из папки при удалении записи

if (Button=nbDelete) then

DeleteFile(DataModule.DBPath+'PIC\'+Format('%.9d%s',[strtoint(DBEdit0.Text),DBEdit.Text]));

end;

3). Аналогично второму способу, только для возвращения курсора на текущую запись используют метод RecNo. Способ был реализован для справочника «Должность» (см. пример). Пример нажатия на кнопку навигатора «Обновить» для формы «Должность»:

// Если нажата кнопка «Обновить»

if (Button=nbRefresh) then

begin

// Присваиваем переменной n номер текущей записи

n:=DBEdit1.DataSource.DataSet.RecNo;

// Вызываем процедуру «обновить»

Refresh;

// Возвращаем курсор на прежнюю запись

dm.DolgnostQuery.RecNo:=n;

end;

Для других форм следует указать другие интервалы обновления в соответствии с частотой их использования.

Обработка исключительных ситуаций

Проверка на ввод некорректных записей

Для того чтобы осуществлять проверку на корректность вводимых записей, необходимо непосредственно в самом модуле DM выделить необходимый запрос – рисунок 36.

Рисунок 35 - Обработка некорректного ввода данных

Далее необходимо в свойствах BeforeInsert (до вставки), BeforeEdit (до редактирования), BeforePost (до сохранения), BeforeRefresh (до обновления) и возможно в некоторых других свойствах (в зависимости от запроса) прописать проверку на корректный ввод. Причем, в разделе uses модуля DM необходимо указать все модули, к которым будет обращаться этот модуль DM при осуществлении проверки (возможно еще придется подключать модули Messages, Dialogs).

Например, проверка на ввод некорректных данных может осуществляться следующим способом:

procedure TDM.SotrQueryBeforeInsert(DataSet: TDataSet);

begin

if (S_sotrudnikiForm.DBEdit3.Text='') or (S_sotrudnikiForm.DBEdit4.Text='') then

begin

MessageDlg('Введите все данные!',mtError,[mbOk],0);

Abort;

end;

end;

Результат работы представлен на рисунке 41.

Рисунок 41 - Обработка исключительных ситуаций

65