Learner
Learner

Reputation: 165

TStringList's Object change automatically

I am created two stringList BookmarkedFields and BookmarkedRecord

BookmarkedFields it contains column name of the dataset BookmarkedRecord it like field:fieldValue field is column name from BookmarkedFields fieldValue is value according to column

Here is procedure to stored the record in the stringList as column and column's value for record.

procedure TBkmrgString.GetIQBookmark(ADataset: TDataset);
var
  I : integer;
begin
  ADataset.GetFieldNames(BookmarkedFields);
  for I := 0 to BookmarkedFields.Count - 1 do
  begin
    BookmarkedRecord.AddObject(BookmarkedFields[I], ADataset.FieldByName(BookmarkedFields[I]));
  end;
end;

I try to find that record already stored in stringlist into the dataset. But when start locating into dataset the value in stringlist automatically gets change and it shows the value which is pointed in dataset. Object of stringlist which is automatically get changed.

procedure TBkmrgString.GotoIQBookmark(ADataset: TDataset);
var
 I : Integer;
 a : string;
begin
  ADataset.DisableControls;
  ADataset.First;
  while not ADataset.Eof do
  begin
    I := 0;
    while (I < BookmarkedFields.Count) and
          (ADataset.FieldByName(BookmarkedFields[ I ]).Value =  TField(BookmarkedRecord.Objects[ I ]).Value) do
    begin
      I := I + 1;
    end;
    if I = BookmarkedFields.Count then
      Break
    else
      ADataset.Next;
  end;
  ADataset.EnableControls;
end;

How to tackle from this situation, How did I persists the value in stringlist that stored, Don't want to be automatically changed object of stringlist.

Upvotes: 1

Views: 464

Answers (2)

MartynA
MartynA

Reputation: 30745

Suppose you have a StringList containing one or more entries like this

FieldNameN=FieldValueN

Obviously, this is much simpler than using two separate TStringLists. Then, the following code will locate the dataset record matching these fieldname/value pairs. It uses four utility functions to convert the contents of the StringList into the arguments to be passed the the dataset's Locate function. These utility functions are quite lengthy but useful additions to a general purpose toolbox. HeadOf and TailOf are useful for parsing Name/Value pairs. MakeFieldNameList' andMakeFieldValueListare useful for constructing the arguments to be passed toTDataSet.Locate`.

function LocateUsingStrings(ADataSet : TDataSet; Strings : TStrings) : Boolean;
var
  FieldNames : String;
  FieldValues : Variant;
begin
  FieldNames := MakeFieldNameList(Strings);
  FieldValues := MakeFieldValueList(Strings);
  Result := ADataSet.Locate(FieldNames, FieldValues, []);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if LocateUsingStrings(MyDataSet, Memo1.Lines) then
    Caption := 'found'
  else
    Caption := 'Not found';
end;

The utility functions are

function HeadOf(const Input : String; const Delim : String) : String;
//  With Input 'Name=Value', returns Name
var
  P     : integer;
begin
  P := Pos(Delim, Input);
  if P > 0 then
    Result := Copy(Input, 1, Pred(P))
  else
    Result := Input;
end;

function TailOf(const Input : String; const Delim : String) : String;
//  With Input 'Name=Value', returns Value
var
  P1,
  P2,
  Len : Integer;
begin
  P2 := MaxInt;
  Len := Length(Input);
  P1 := Pos(Delim, Input);
  if P1 > 0 then begin
    P2 := P1 + Length(Delim);
    if P2 <= Len then
      Result := Copy(Input, P2, Len)
    else
      Result := Input;
  end
  else
    Result := '';
end;

function MakeFieldNameList(Strings : TStrings) : String;
var
  i : Integer;
begin
  // Trim off leading and trailing blank lines
  Strings.Text := Trim(Strings.Text);

  Result := '';
  for i := 0 to Strings.Count - 1 do begin
    if Result <> '' then
      Result := Result + ';';
    Result := Result + HeadOf(Strings[i], '=');
  end;
end;

function MakeFieldValueList(Strings : TStrings) : Variant;
var
  i : Integer;
  Value : String;
begin
  // Trim off leading and trailing blank lines
  Strings.Text := Trim(Strings.Text);

  if Strings.Count = 1 then begin
    Value := TailOf(Strings[0], '=');
    Result := Value;
  end
  else begin
    Result := VarArrayCreate([0, Strings.Count -1], varVariant);
    for i := 0 to Strings.Count - 1 do begin
      Value := TailOf(Strings[i], '=');
      Result[i] := Value;
    end;
  end;
end;

If you really must encode your field values as Objects in your StringList, the code could readily be adapted to that.

Btw, the MakeFieldNameList, MakeFieldValueList and LocateUsingStrings functions have a TStrings input parameter rather than a TStringList one so that they aren't restricted to TStringlists.

Btw, Locate does not in general require keyfields, if you mean fields in an index on the table.

Upvotes: 1

Andrew
Andrew

Reputation: 1866

You are not storing field value in stringlist. This code

BookmarkedRecord.AddObject(BookmarkedFields[I], ADataset.FieldByName(BookmarkedFields[I]));

adds TField object to TStringList. Field, not record. TField object is not storing value. It points to field, and every time you call it, value of current record in dataset will be returned. Not "remembered", only current.

If you need to remember value, you can do something like this:

BookmarkedRecord.AddObject(BookmarkedFields[I], TObject(ADataset.FieldByName(BookmarkedFields[I]).AsInteger));

This example is applicable for integer field.

Upvotes: 2

Related Questions