Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Delphi TField.OnValidate restore the original value without raising exception?

I usually implement validation logic as:

procedure TMyDM.IBQueryAMOUNTValidate(
  Sender: TField);
begin
  inherited;
  if Sender.AsFloat>100
    then raise Exception.Create('Amount is too large!');
end;

The question is - is there chance not to raise Exception in the OnValidate (which stops further processing), but to restore silently original value in the OnValidate and proceed with OnChange, CheckBrowseMode and all the GUI updates that are called by the CheckBrowseMode/Post?

Of course, I know that I can always replace OnValidate logic with OnChange logic that handles OldValue and NewValue but it seems to me that code would be cleaner it I stick with OnValidate.

like image 492
TomR Avatar asked Mar 06 '23 05:03

TomR


2 Answers

Don't use OnValidate to do anything apart from raise an exception to reject the Sender's value.

To see why, set up a simple test app consisting of a TClientDataSet with fields ID (Integer) and Name (String(20)), TDataSource, TDBNavigator, TDBGrid and TDBEdit for the Name field. Add the following code:

procedure TForm1.ClientDataSet1NameValidate(Sender: TField);
begin
  if Sender.AsString = 'x' then
    Sender.DataSet.Cancel;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ClientDataSet1.CreateDataSet;
  ClientDataSet1.InsertRecord([1, 'a']);
  ClientDataSet1.InsertRecord([2, 'b']);
  ClientDataSet1.InsertRecord([3, 'c']);
end;

Compile, run, and enter 'x' (without the quotes) into the DBEdit. Then click Save on the DBNavigator.

Notice that the edit is cancelled but the 'x' remains in the DBEdit. This is in Delphi 10.2.3, btw. Back in D7 days, it was even worse - the wrong row in the DB grid would show the 'x'!

The other thing is that OnValidate is never actually called in TDataSet's methods, only descendants, e.g. TClientDataSet. So there is no guarantee that in general OnValidate will be called at all or at the right time - it's up to the dataset-type's author to get it right.

So I think the answer to your q is "No", leave the OnValidate to raise exceptions but no more.

like image 122
MartynA Avatar answered May 10 '23 18:05

MartynA


It seems to me, the only purpose of OnValidate event is raising exceptions. From Delphi help (http://docwiki.embarcadero.com/Libraries/Berlin/en/Data.DB.TField.OnValidate):

To reject the current value of the field from the OnValidate event handler, raise an exception ...
If writing the data does not raise an exception, the OnChange event handler is called to allow a response to the change.

For tasks of validation I use OnSetText event, which gives me possibility to silent restore original value if new one is not acceptable.

like image 20
Miamy Avatar answered May 10 '23 17:05

Miamy