delphidatasetdelphi-2006

Delphi - TDataSet determine if it was modified when is in insert/edit state


how can I find out if an data-aware component field has been modified when the dataset is already in Insert state? I want to know if a field was 'really' modified. (I don't care if the user has input something in a field and after that erase everything, this mean that a modification occured).

DataSet.Modified, DataSet.UpdateStatus or ChangeCount are not solving my problem.

LE: let me explain more in depth this. so, initial dataset looks like

-------------------------------------
|PK  | Field1| Field2| Field3|Field4|
-------------------------------------
| 1  |  a    | b     | c     | d    |  
-------------------------------------

after insert

-------------------------------------
|PK  | Field1| Field2| Field3|Field4|
-------------------------------------
| 2  |       |       |       |      |  
-------------------------------------
| 1  |  a    | b     | c     | d    |  
-------------------------------------

when the dataset is really modified

-------------------------------------
|PK  | Field1| Field2| Field3|Field4|
-------------------------------------
| 2  | avalue|       |       |      |  
-------------------------------------
| 1  |  a    | b     | c     | d    |  
-------------------------------------

Solution

  • You could hack the DataSet to change it's Modified property on AfterInsert/AfterEdit (and set initial/default values) and later test for DataSet.Modified (e.g. on before post).
    To determine which specific fields were modified, I hold a copy of the initial record e.g.:

    type
      TDataRecord = array of record
        FieldName: string;
        Value: Variant;
      end;
    
    type
      TForm1 = class(TForm)
        ... 
      private
        FInitRecord, FPostRecord: TDataRecord;
      end;
    
    function GetDataRecord(DataSet: TDataSet): TDataRecord;
    var
      I: Integer;
    begin
      Result := nil;
      if Assigned(DataSet) then begin
        SetLength(Result, DataSet.FieldCount);
        for I := 0 to DataSet.FieldCount - 1 do begin
          Result[I].FieldName := DataSet.Fields[I].FieldName;
          Result[I].Value := DataSet.Fields[I].Value;
        end;
      end;
    end;
    
    type
      TDataSetAccess = class(TDataSet);
    
    procedure TForm1.ADODataSet1AfterInsert(DataSet: TDataSet);
    begin
      // set initial values 
      ADODataSet1.FieldByName('PK').Value := GetMyPKValue;
      ADODataSet1.FieldByName('DateCreated').AsDateTime := Now(); 
      // un-modify
      TDataSetAccess(ADODataSet1).SetModified(False);
      // save initial record
      FInitRecord := GetDataRecord(ADODataSet1);
    end;    
    
    procedure TForm1.ADODataSet1BeforePost(DataSet: TDataSet);
    var
      I: Integer;
    begin
      if ADODataSet1.Modified then
      begin
        FPostRecord := GetDataRecord(ADODataSet1);
        Memo1.Lines.Clear;
        for I := 0 to Length(FPostRecord) - 1 do begin
          if FPostRecord[I].Value <> FInitRecord[I].Value then
            Memo1.Lines.Add(Format('Field %s was modified', [FPostRecord[I].FieldName]));
        end;
      end;
    end;
    

    Well, It's the abstract idea anyway. You could sub-class your TDataSet like I do, and implement this feature directly inside your TDataSet component.