Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TClientDataSet Traverse & Delete record cause some record being traverse twice in the while-loop (If with Index)

I have the following code which traverse all data in the TClientDataSet, my purpose is to delete all records except DocKey=20381.

But with the following codes, you will notice record with DocKey=20381 being traversed twice (traverse times = 6, which suppose to be 5 times as we only have 5 records in TClientDataSet).

If we enable this line -> D.IndexFieldNames := 'DocKey', then the data will traverse correctly. May I know is this a Delphi bug? Or any way to solve this besides using IndexFieldNames?

var
  D: TClientDataSet;
begin
  D := TClientDataSet.Create(Self);
  with D do begin
    FieldDefs.Add('DocKey', ftInteger);
    CreateDataSet;
    AppendRecord([20157]);
    AppendRecord([20162]);
    AppendRecord([20381]);
    AppendRecord([20372]);
    AppendRecord([20377]);
  end;
  // D.IndexFieldNames := 'DocKey';

  D.First;
  while not D.Eof do begin
    if D.Fields[0].AsInteger = 20381 then
      D.Next
    else
      D.Delete;
  end;
end;
like image 524
Sherlyn Chew Avatar asked Sep 01 '25 18:09

Sherlyn Chew


1 Answers

This behavior is as designed and documented

If the record deleted was the last record in the dataset, then the previous record becomes the current record.

20157 -> delete
20162 -> delete
20381 -> next
20372 -> delete
20377 -> delete (last record -> goto previous record -> not eof)

With this line

D.IndexFieldNames := 'DocKey';

the not to be deleted record becomes the last record in dataset and therefore there is no delete at the last record and not that behavior.

20157 -> delete
20162 -> delete
20372 -> delete
20377 -> delete
20381 -> next

UPDATE

If you want to avoid this - for any reasons I did not know or I could imagine - just check, if the current RecNo is decreased.

var 
  D: TClientDataSet;
  LRecNo : Integer;
begin
  D := TClientDataSet.Create(Self);
  with D do begin
    FieldDefs.Add('DocKey', ftInteger);
    CreateDataSet;
    AppendRecord([20157]);
    AppendRecord([20162]);
    AppendRecord([20381]);
    AppendRecord([20372]);
    AppendRecord([20377]);
  end;
  // D.IndexFieldNames := 'DocKey';

  D.First;
  while not D.Eof do 
  begin

    LRecNo := D.RecNo;

    if D.Fields[0].AsInteger = 20381 then
      D.Next
    else
      D.Delete;

    if LRecNo > D.RecNo then
      Break;

  end;
end;
like image 152
Sir Rufo Avatar answered Sep 04 '25 07:09

Sir Rufo