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?).