Способы редактирования данных
Несмотря на декларированные недостатки технологии dbExpress – однонаправленные курсоры и невозможность редактирования – существуют программные способы уменьшить масштаб проблемы или даже решить ее.
Во-первых, в нашем распоряжении имеется компонент TSimpleDataSet, который реализует двунаправленный курсор и обеспечивает редактирование данных путем их кэширования на клиентской стороне.
Во-вторых, редактирование можно обеспечить настройкой и выполнением запросов SQL INSERT, UPDATE и DELETE.
У каждого способа есть свои преимущества и недостатки.
Компонент TSimpleDataSet безусловно хорош. Он технологичен, относительно прост в использовании и, главное, прячет всю функциональность за несколькими свойствами и методами. Но локальное кэширование изменений подходит далеко не для всех приложений.
Например, при многопользовательском интенсивном доступе к данным с их редактированием при локальном кэшировании могут возникнуть проблемы с целостностью и адекватностью данных. Самый распространенный пример: продавец в строительном супермаркете, обслуживая покупателя в пик летних ремонтов, резервирует несколько наименований ходовых товаров. Но покупатель замешкался, выбирая обои и плитку. А за это время другой продавец уже продал другому покупателю (заказ первого покупателя еще находится в локальном кэше!) часть его товаров.
Конечно, фиксацию изменений на сервере можно выполнять после локального сохранения каждой записи, но это приведет к загрузке соединения и снижению эффективности системы.
Использование модифицирующих запросов, с одной стороны, позволяет оперативно вносить изменения в данные на сервере, а с другой – требует больших затрат на программирование и отладку. Сложность кода в этом случае существенно выше.
Рассмотрим небольшой пример реализации обоих способов. Приложение Demo DBX использует соединение с сервером InterBase. Подключена тестовая база данных \Borland Shared\Data\MastSQL.gdb.
Листинг 17.1. Пример приложения dbExpress с редактируемыми наборами данных.
implementation {$R *.dfm} procedure TfmDemoDBX.FormCreate(Sender: TObj ect); begin tblVens.Open; cdsGusts.Open; end; procedure TfmDemoDBX.FormDestroy(Sender: TObject); begin tblVens.Close; cdsCusts.Close; end; {Editing feature with updating query} procedure TfmDemoDBX.tblVensAfterScroll(DataSet: TDataSet); begin edVenNo.Text: = tblVens.FieldByName('VENDORNO').AsString; edVenName.Text: = tblVens.FieldByName('VENDORNAME').AsString; edVenAdr.Text: = tblVens.FieldByName('ADDRESS1')AsString; edVenCity.Text: = tblVens.FieldByName('CITY').AsString; edVenPhone.Text: = tblVens.FieldByName('PHONE').AsString; end; procedure TfmDemoDBX.sbCancelClick(Sender: TObject); begin tblVens.First; end; procedure TfmDemoDBX.sbNextClick(Sender: TObject); begin tblVens.Next; end; procedure TfmDemoDBX.sbPostClick(Sender: TObject); begin with quUpdate do try ParamByName(4dx').Aslnteger: = tblVens.FieldByName('VENDORNO').Aslnteger; ParamByName('No').AsString: = edVenNo.Text; ParamByName('Name').AsString: = edVenName.Text; ParamByName('Adr').AsString: = edVenAdr.Text; ParamByName('City').AsString: = edVenCity.Text; ParamByName('Phone1).AsString: = edVenPhone.Text; ExecSQL; except MessageDlg('Vendor''s info post error', mtError, [mbOK], 0); tblVens.First; end; end; {Editing feature with cached updates} procedure TfmDemoDBX.cdsCustsAfterPost(DataSet: TDataSet); begin cdsCusts.ApplyUpdates(-1); end; procedure TfmDemoDBX.cdsCustsReconcileError(DataSet: TCustomClientDataSet; E: EReconcileError; UpdateKind: TUpdateKind; var Action: TReconcileAction); begin MessageDlg('Customer''s info post error', mtError, [mbOK], 0); cdsCusts.CancelUpdates; end; end.