Hi,
here are diffs with changes, I hope they will be good for all TDataSet descendants (those specific to FPC and also those which are also for use in Delphi) Code which is general (and is used repeatedly) is placed in TField methods and only small code remains which must be placed into each TDataSet descendant. (I patched only TBufDataSet, but later can be updated also other TDataSet descendants ... remove redundant code and add Field.Validate(...))
Thanks
-Laco.


The whole code, which is repeated (and can be put in one place) is:

if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then
begin
  DatabaseErrorFmt(SNotEditing,[Name],self);
  exit;
end;
if (Field.FieldNo>0) and not (State in [dsSetKey, dsFilter]) then
begin
if Read OnlythenDatabaseErrorFmtSReadOnlyField,[Field.DisplayName],
Self);
  Field.Validate(Buffer);
end;

You are right in your dislike.

I will create a 'BeforeSetFieldData' in TDataset and put the code in there,
and the same for 'AfterSetFieldData' with the OnChange code.

OK,
Then please do not forget commit necessary changes also in other descendants (not only in TCustomBufDataSet but also in TParadox, TMemDataset, TFixedFormatDataSet, TDbf) to completelly fix 'missing onvalidate call' problem.
Thanks

I am still thinking about this.
I have other solution, which is relative simple , puts base logic into base TField methods (so all TDataSet descendants can benefit from it) and does not negatively affect existing TDataSet descendants and does not require introduce new methods (BeforeSetFieldData, AfterSetFieldData).
Let's distributes repeating used code as follows:

1. base checks "before" into procedure TField.SetData(Buffer: Pointer; NativeFormat : Boolean);

 820 begin
 821   If Not Assigned(FDataset) then
 822     DatabaseErrorFmt(SNoDataset,[FieldName]);

if not (State in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then //here should be IMO also dsNewValue
         DatabaseErrorFmt(SNotEditing,[FDataSet.Name],FDataSet);

if ReadOnly and (FieldNo>0) and not (FDataSet.State in [dsSetKey, dsFilter]) then
         DatabaseErrorFmt(SReadOnlyField, [DisplayName], Self);

 829   FDataSet.SetFieldData(Self,Buffer, NativeFormat);
--------------------------------------------------------------------------

2. into procedure TField.Validate(Buffer: Pointer);

 892 begin
if FData Set.Statein[dsSetKey,dsFilter]thenExit 893 If assigned(OnValidate) Then

--------------------------------------------------------------------------

3. "after call" into procedure TDataSet.SetFieldData(Field: TField; Buffer: Pointer);
    begin
      if not (State in [dsCalcFields, dsFilter, dsNewValue]) then
        DataEvent(deFieldChange, Ptrint(Field));
    end;

--------------------------------------------------------------------------

And now all what we must do, is put into method SetFieldData in TDataSet descendants one line:

Field.Validate(Buffer);
and one line at end:

inherited; //calls "field change" ... this is done by all TDataSet descendants in fcl-db as a last thing


It is only draft, so some detils may be changed ... ;-)
What do you think ?

Laco.



--- bufdataset.pas.ori  Sun Feb 20 14:31:16 2011
+++ bufdataset.pas      Wed Apr 13 09:07:18 2011
@@ -1830,14 +1830,10 @@ var CurrBuff : pointer;
     NullMask : pbyte;
 
 begin
-  if not (state in [dsEdit, dsInsert, dsFilter, dsCalcFields]) then
-    begin
-    DatabaseErrorFmt(SNotEditing,[Name],self);
-    exit;
-    end;
   CurrBuff := GetCurrentBuffer;
-  If Field.Fieldno > 0 then // If = 0, then calculated field or something
+  If Field.FieldNo > 0 then // If = 0, then calculated field or something
     begin
+    Field.Validate(Buffer);
     NullMask := CurrBuff;
 
     inc(CurrBuff,FFieldBufPositions[Field.FieldNo-1]);
--- fields.inc.ori      Wed Apr 13 08:50:56 2011
+++ fields.inc  Wed Apr 13 09:05:04 2011
@@ -820,12 +820,10 @@ procedure TField.SetData(Buffer: Pointer
 begin
   If Not Assigned(FDataset) then
     DatabaseErrorFmt(SNoDataset,[FieldName]);
-  if (FieldNo>0) and not (FDataSet.State in [dsSetKey, dsFilter]) then
-    begin
-    if ReadOnly then 
-      DatabaseErrorFmt(SReadOnlyField, [DisplayName], Self); 
-    Validate(Buffer);
-    end;
+  if not (FDataSet.State in dsWriteModes) then
+    DatabaseErrorFmt(SNotEditing,[FDataSet.Name],FDataSet);
+  if ReadOnly and (FieldNo>0) and not (FDataSet.State in [dsSetKey, dsFilter]) 
then
+    DatabaseErrorFmt(SReadOnlyField, [DisplayName], Self);
   FDataSet.SetFieldData(Self,Buffer, NativeFormat);
 end;
 
@@ -890,7 +888,7 @@ end;
 procedure TField.Validate(Buffer: Pointer);
 
 begin
-  If assigned(OnValidate) Then
+  If assigned(OnValidate) and not (FDataSet.State in [dsSetKey,dsFilter]) Then
     begin
     FValueBuffer:=Buffer;
     FValidating:=True;
_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply via email to