Question

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    |  
-------------------------------------
Was it helpful?

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.

OTHER TIPS

When the state is dsInsert use:

VarCompareValue(Field.NewValue, Unassigned) = vrNotEqual;

dsEdit use:

OldValue <> Value;

Do not use this in dsInsert state as in numeric Fields 0 is equal Unassigned:

Field.NewValue <> Unassigned

Until now I found a solution, which seems to work. Solution consist in: - link a datasource to the tdataset descendant - a global boolean variable is set to false on the dataset OnAfterScroll event, and true on the datasources's OnDataChange event.

From the tests I performed on the application until now, it seems that this work-around is working. I need now to investigate all the events which occur and need special treatment for not altering the state of the global variable in the process.

Any other ideas are welcomed

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top