Главная » Delphi » Редактирование данных в клиентском приложении

0

Все записи, переданные сервером компоненту  TClientDataSet, хранятся в его свойстве Data. Это свойство содержит представление пакета  данных  DataSnap с фор мате  Variant. Компоненту TClientDataSet известно, как такой  пакет  данных  пре образовать в более  удобную форму.  Использование типа  Variant обусловлено тем,

что для подсистемы СОМ доступно  ограниченное количество типов данных.

При  выполнении операций с записями набора данных  клиента копии вставленных, модифицированных или удаленных  записей помещаются в свойство Delta. Этим обес печивается высокая эффективность  приложений DataSnap при  передаче обновлений обратно в серверную часть приложения и, в конечном счете, в базу данных.

Для свойства Delta используется чрезвычайно эффективный формат. В этом свойстве каждой операции вставки  или удаления соответствует одна запись, а для каждого  обновле ния — две записи. Обновляемые записи хранятся тоже достаточно эффективно. Исходная запись  содержится в первой записи, тогда  как соответствующая ей модифицируемая за пись хранится во второй записи обновления. Однако  в модифицированной записи содер жатся лишь измененные поля.

Интересно то,  что  свойство Delta совместимо со свойством Data. Другими  сло вами, хранящееся в нем значение можно  напрямую присвоить свойству  Data другого компонента ClientDataSet. Благодаря этому  текущее  содержимое свойства Delta можно анализировать в любой момент.

Для редактирования данных  можно  использовать различные методы  компонента TClientDataSet. В дальнейшем мы  будем называть их  методами  управления измене ниями (change control method). Они  позволяют различными способами модифициро вать данные, внесенные в набор  данных клиента.

НА ЗАМЕТКУ

Компонент TClientDataSet оказался гораздо более полезным, чем предполагалось из- начально. Он обеспечивает прекрасный способ хранения таблиц в оперативной памяти (in-memory), что напрямую никак не связано с технологией DataSnap. Кроме того, по- скольку компонент TClientDataSet может использоваться для передачи данных через свойство Data и другие свойства Delphi, он оказывается полезным и при реализации различных шаблонов объектно-ориентированного программирования. Обсуждение этих приемов выходит за рамки излагаемого в настоящей главе материала. Более подробная информация по данной теме находится на Web-странице по адресу: http://xapware.com или http://xapware.com/ddg.

Отмена внесенных изменений

Большинство пользователей знакомы с текстовыми процессорами, в которых под держивается команда  отмены изменений (Undo). Воспользовавшись ею, можно  отме нить  последнее внесенное изменение и вернуться в исходное состояние. То же самое можно  осуществить и с помощью вызова  метода  cds.Customer.UndoLastChange() компонента TClientDataSet. Используемый при  этом  стек  имеет  неограниченную длину, так что при необходимости есть возможность вернуться к самому началу сеанса редактирования. Параметр, передаваемый этому методу,  определяет, нужно ли пози ционировать курсор на соответствующую запись.

Если необходимо отменить все обновления одновременно, то последовательный вызов  метода  UndoLastChange() является не  самым  лучшим  решением. Чтобы от менить все изменения, вносимые на протяжении одного  сеанса  редактирования, сле дует просто вызвать метод cdsCustomer.CancelUpdates().

Возврат к исходной версии

Для возвращения определенной записи в исходное состояние (т.е. в такое,  в котором она  находилась в момент извлечения из базы  данных) можно  воспользоваться другим методом. Чтобы сделать  это,  переместите курсор  в наборе данных  клиента на запись, которую нужно восстановить, и вызовите метод cdsCustomer.RevertRecord().

Транзакции клиента: свойство SavePoint

И,  наконец,  свойство SavePoint позволяет клиенту   использовать  транзакции. Данное свойство идеально подходит для разработки сценариев типа  “что если”. При своив   значение  свойства  SavePoint некоторой  переменной,  можно   сохранить “моментальный снимок”  данных.  После  этого  пользователь может  продолжать редак тирование. Если в какой либо  момент пользователь решит, что  в снимке  содержатся именно те данные, которые ему нужны,  то можно  вернуть  значения сохраненные ра нее в свойстве SavePoint. При  этом набор  данных  клиента вернется в то состояние, в котором он находился до сохранения. Обратите внимание: для реализации сложно го сценария может понадобиться несколько уровней SavePoint.

CОВЕТ

Позволим себе одно предостережение относительно свойства SavePoint: при вызове метода UndoLastChange() значение этого свойства можно “испортить”. Например, предположим, что пользователь выполнил редактирование двух записей и сохранил значение свойства SavePoint. Затем он внес изменения в следующую запись, после чего для отмены внесенных изменений дважды воспользовался методом UndoLast- Change(). Поскольку компонент TClientDataSet перешел в состояние, предшест- вующее сохраненному в свойстве SavePoint, то значение этого свойства стало неоп- ределенным.

Согласование данных

По завершении внесения изменений в локальную  копию  данных, содержащуюся в компоненте TClientDataSet, эти  изменения необходимо перенести в базу данных. Указанное можно  осуществить с помощью метода  cdsCustomer.ApplyUpdates(). При вызове этого метода приложению сервера будет передано свойство Delta, послечего  поступившие изменения будут внесены в базу данных  в соответствии с механиз мом согласования, установленным для обрабатываемого набора данных.  Все обновле ния  выполняются в рамках  контекста одной  транзакции. Кратко остановимся на об работке ошибок  в ходе этого процесса.

Параметр, передаваемый методу  ApplyUpdates(), определяет количество оши бок,  появившихся в процессе обновления, после  возникновения которых считается, что  обновление завершилось неудачно.  В этом  случае  все внесенные изменения по следовательно отменяются. В данном  контексте под ошибками (errors) подразумевает ся  неудачный поиск  по  ключу,  нарушение целостности  ссылок  или  любые  другие ошибки базы данных.  Если для этого  параметра установлено нулевое  значение, то тем самым  задается недопустимость любых  ошибок. Таким  образом, при  возникновении какой либо ошибки, все внесенные изменения в базе данных  зафиксированы не будут. Это значение используется чаще  всего,  поскольку  оно  наиболее точно соответствует основным принципам использования баз данных.

Однако  при желании можно задать и ненулевое число допустимых ошибок. Тогда в базу данных  будут перенесены только  все успешные записи. Предельным расширени ем этой  концепции является передача в качестве параметра метода  ApplyUpdates() значения -1. В этом случае приложением DataSnap в базе данных  будет сохранена ка ждая отдельная запись, которую  можно  сохранить, без учета количества произошед ших ошибок. Другими  словами, при использовании этого  значения транзакция всегда будет завершена успешно.

Если необходимо получить полный контроль над процессом обновления, в том чис ле  возможность изменения операторов SQL,  используемых для  вставки, обновления или удаления, то можно  воспользоваться обработчиком события TDataSetProvider. BeforeUpdateRecord(). Например, при удалении  записи может потребоваться не уда лять ее из базы данных  физически. Вместо этого  есть возможность установить флажок, сообщающий приложениям, что  данная  запись  недоступна. Позднее можно  пересмот реть  такие  записи и выполнить операцию физического удаления.  В следующем  фраг менте кода демонстрируется, как это можно осуществить:

procedure TDataModule1.Provider1BeforeUpdateRecord(Sender: TObject; SourceDS: TDataset; DeltaDS: TClientDataset; UpdateKind: TUpdateKind; var Applied: Boolean);

begin

if UpdateKind=ukDelete then begin

Query1.SQL.Text:=’update CUSTOMER set STATUS="DEL" where

? ID=:ID'; Query1.Params[0].Value:=DeltaDS.FieldByName(‘ID’).OldValue; Query1.ExecSQL;

Applied:=true;

end;

end;

В процессе управления потоком и содержимым процесса обновления можно  соз дать любое  количество запросов, опираясь на различные факторы, например на зна чение параметра UpdateKind и значения полей  в наборе DataSet. При  просмотре или модификации записей, содержащихся в параметре DeltaDS, удостоверьтесь, что используются свойства OldValue и  NewValue соответствующего объекта  TField. При  использовании свойства TField.Value или TField.AsXXX можно  получить не предсказуемый результат.Кроме  того,  при  передаче обновлений в базу данных  можно  использовать биз нес правила или вообще  отменить передачу.  Любое  исключение, возникшее на этом этапе, будет передано механизму  обработки ошибок  DataSnap, который рассматри вается  ниже.

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

Первая остановка при  ошибке  осуществляется при  обработке события DataSet- Provider.OnUpdateError. Этот обработчик прекрасно подходит для обработки ожи даемых ошибок или для их устранения без вмешательства клиента.

Конечным получателем ошибок  является клиентское приложение, в котором пользователю можно  позволить самому принять решение о том, как поступить с оши бочной записью. Для этого необходимо определить обработчик события TClientDa- taSet.OnReconcileError.

Такой подход оказывается исключительно полезным,  поскольку  DataSnap  осно

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

Использование стандартного диалогового окна согласования ошибок

К счастью, компания Borland предоставила в распоряжение разработчика стандарт ное диалоговое окно,  которое можно  использовать для отображения ошибок. Это окно показано на рис. 21.6. Исходный код такого  модуля также  доступен, поэтому  при  необ ходимости его можно  модифицировать. Для использования данного диалогового окна выберите в меню File пункт New, а затем — пиктограмму Reconcile Error Dialog во вкладке Dialogs. Не забудьте удалить этот модуль из списка Autocreate Forms, в противном случае при компиляции возникнут ошибки.

Рис. 21.6. Диалоговое окно Reconcile Error в действииПочти все действия этого  модуля реализованы в функции HandleReconcileEr- ror(), связанной с событием OnReconcileError. На практике обработчик события OnReconcileError обычно вызывает функцию HandleReconcileError. Благодаря этому конечный пользователь на клиентской машине  получает  возможность взаимо действовать с процессом согласования ошибок  на сервере и определять способ  обра ботки этих ошибок. Обработчик события OnReconcileError может быть реализован следующим образом:

procedure TMyForm.CDSReconcileError(Dataset: TCustomClientDataset; E: EReconcileError; UpdateKind: TUpdateKind; var Action: TReconcileAction);

begin

Action:=HandleReconcileError(Dataset, UpdateKind, E);

end;

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

•    raSkip. Не обновлять текущую запись базы данных. Оставить измененную за

пись в буфере  клиента.

•  raMerge. Объединить поля текущей  записи с записью базы данных.  Эта запись не будет применяться к уже вставленным записям.

•  rаCorrect. Обновить запись  базы  данных  с использованием заданных значе ний.  При  выборе этого  действия в диалоговом окне  Reconcile Error значения можно  редактировать в сетке  (grid). Этот метод нельзя применять, если запись базы данных редактировалась другим пользователем.

•  raCancel. Не обновлять запись базы данных и удалить ее из буфера клиента.

•    raRefresh. Обновить запись в буфере клиента с использованием данных теку

щей записи  базы.

•  raAbort. Полностью прервать операцию обновления.

Данные параметры имеют  смысл (а значит, и отображаются) не во всех случаях. Чтобы действия raMerge и raRefresh были  доступны, запись  должна  была  иден тифицирована приложением с помощью первичного ключа базы данных.  Для этого необходимо  установить  свойство  TField.ProviderFlags.pfInKey компонента TDataset в состояние True для всех полей, указанных в первичном ключе.

Источник: Тейксейра, Стив, Пачеко, Ксавье.   Borland Delphi 6. Руководство разработчика. : Пер.  с англ. — М. : Издательский дом “Вильямс”, 2002. —  1120 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии