Delphi ADO : Locate with dataset filter on bug

牧云@^-^@ 提交于 2019-12-01 08:20:24
kobik

The problem with TCustomADODataSet.Locate is that it's internally using Recordset.Clone and trying to locate a record in the cloned recordset, without setting the filter to the cloned recordset (see ADODB TCustomADODataSet.LocateRecord).

From the Remarks in the docs:

The Filter property of the original Recordset, if any, will not be applied to the clone. Set the Filter property of the new Recordset to filter the results. The simplest way to copy any existing Filter value is to assign it directly, as follows. rsNew.Filter = rsOriginal.Filter The current record of a newly created clone is set to the first record.

I have been using my own simple Locate function for filtered ADO DataSets: Basically, storing the current bookmark, moving to the first record and iterating the DataSet until it found a match. If no match found restore the previous bookmark.
Bellow is a really limited implementation that worked for me (a lot of todo tho for a perfect solution):

class function TData.Locate(DataSet: TDataSet; const KeyFields: string;
  const KeyValues: Variant; Options: TLocateOptions): Boolean;
{ a very simple Locate function - todo: TLocateOptions & multiple KeyFields/KeyValues }
var
  BM: TBookmarkStr;
begin
  Result := False;
  if DataSet.IsEmpty then Exit;
  BM := DataSet.Bookmark;
  DataSet.DisableControls;
  try
    DataSet.First;
    while not DataSet.Eof do
    begin
      if DataSet.FieldByName(KeyFields).Value = KeyValues then
      begin
        Result := True;
        Break;
      end;
      DataSet.Next;
    end;
    if not Result then DataSet.Bookmark := BM;
  finally
    DataSet.EnableControls;
  end;
end;

Another option is to patch ADODB.pas TCustomADODataSet.LocateRecord and set the FLookupCursor.Filter to match the current dataset filter. This option is acceptable as long as you patch ADODB.pas as a new copy placed in your project folder.

Yet another option is to use TCustomADODataSet.Recordset.Find method (See also: How to use a RecordSet.Find with TADOQuery?).

Try this:

ADO.Filter := 'Name=' + QuotedStr('John');
ADO.Filtered := True; // Now, its only 2 rows in dataset
ADO.Locate('Value',2,[]);

The third parameter of the Locate function is for locate options, which I've left empty in the example above. You can read up on Locate here http://docwiki.embarcadero.com/RADStudio/XE7/en/Using_Locate and here http://docwiki.embarcadero.com/Libraries/XE7/en/Data.DB.TDataSet.Locate

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!