3.8.4. Implementing the Customer Module
Modal forms are often used to add a new record or to edit an existing one. Once the modal form is closed by the mrOK result, the changes are posted to the database. Database-aware visual components are usually used to create this kind of form. These components enable you to display the values of some fields from the current record and immediately accept the user’s changes in the corresponding fields if the dataset is in the Insert/Edit mode, i.e. before Post.
The only way to switch the dataset to Insert/Edit mode is by starting a write transaction. So, if somebody opens a form for adding a new record and leaves for a lunch break, we will have an active transaction hanging until the user comes back from lunch and closes the form. This uncommitted edit can inhibit garbage collection, which will reduce performance. There are two ways to solve this problem:
Use the
CachedUpdatesmode, which enables the transaction to be active just for a very short period (to be exact, just for the time it takes for the changes to be applied to the database).Give up using visual components that are data-aware. This approach requires some additional effort from you to activate the data source and pass user input to it.
We will show how both methods are implemented. The first method is much more convenient to use. Let’s examine the code for editing a customer record:
procedure TCustomerForm.actEditRecordExecute(Sender: TObject);varxEditorForm: TEditCustomerForm;beginxEditorForm := TEditCustomerForm.Create(Self);tryxEditorForm.OnClose := CustomerEditorClose;xEditorForm.DataSource := Customers.DataSource;xEditorForm.Caption := 'Edit customer';Customers.Edit;xEditorForm.ShowModal;finallyxEditorForm.Free;end;end;The Customers property is initiated in the OnCreate event:procedure TCustomerForm.FormCreate(Sender: TObject);beginFCustomers := TDMCustomers.Create(Self);DBGrid.DataSource := Customers.DataSource;end;
We set the CachedUpdates mode for the dataset in the Edit method of the dCustomers module before switching it to the edit mode:
procedure TdmCustomers.Edit;beginqryCustomer.CachedUpdates := True;qryCustomer.Edit;end;
The logic of handling the process of editing and adding a record is implemented in the OnClose event handler for the modal edit form:
procedure TCustomerForm.CustomerEditorClose(Sender: TObject;var Action: TCloseAction);beginif TEditCustomerForm(Sender).ModalResult <> mrOK thenbeginCustomers.Cancel;Action := caFree;Exit;end;tryCustomers.Post;Customers.Save;Action := caFree;excepton E: Exception dobeginApplication.ShowException(E);// It does not close the window give the user correct the errorAction := caNone;end;end;end;
To understand the internal processes, we can study the code for the Cancel, Post and Save methods of the dCustomer data module:
procedure TdmCustomers.Cancel;beginqryCustomer.Cancel;qryCustomer.CancelUpdates;qryCustomer.CachedUpdates := False;end;procedure TdmCustomers.Post;beginqryCustomer.Post;end;procedure TdmCustomers.Save;begin// We do everything in a short transaction// In CachedUpdates mode an error does not interrupt the running code.// The ApplyUpdates method returns the number of errors.// The error can be obtained from the property RowErrortrytrWrite.StartTransaction;if (qryCustomer.ApplyUpdates = 0) thenbeginqryCustomer.CommitUpdates;trWrite.Commit;endelseraise Exception.Create(qryCustomer.RowError.Message);qryCustomer.CachedUpdates := False;excepton E: Exception dobeginif trWrite.Active thentrWrite.Rollback;raise;end;end;end;
Observe that the write transaction is not started at all until the OK button is clicked. Thus, the write transaction is active only while the data are being transferred from the dataset buffer to the database. Since we access not more than one record in the buffer, the transaction will be active for a very short time, which is exactly what we want.
