I have a MasterQry and a SlaveQry on the form . The MasterQry is something like this :
select * from Header where Active = 1
.
On it's AfterScroll event I have following :
select * from Slave where HeadID=:Header.ID
Now if I do :
if MasterQry.Active then MasterQry.Close;
MasterQry.Open;
this works flawlessly if I have more then one record , but it does not work if I have only one .
Even if I do MasterQry.First;
nothing happens.
If I try MasterQry.AfterScroll(MasterQry)
I get an access violation .
I was refactoring my code and was trying to make it more compact , because I did a lot of Open Close Locate ID ( needed to refresh data to get actual status, whether it is locked etc. ) and I did this :
function RefreshQuery(AQuery : TADOQuery; ID : integer) : boolean ; overload;
var AfterOpen,AfterScroll : TDataSetNotifyEvent;
begin
result:=false;
AfterOpen := AQuery.AfterOpen;
AfterScroll := AQuery.AfterScroll;
AQuery.AfterOpen:=nil;
AQuery.AfterScroll:=nil;
if AQuery.Active then AQuery.Close;
AQuery.Open;
if not AQuery.Locate('id', ID, []) then
result:=false
else
result:=true;
AQuery.AfterOpen:=AfterOpen;
AQuery.AfterScroll:=AfterScroll;
if Assigned(AQuery.AfterScroll) then
AQuery.AfterScroll(AQuery);
end;
Please NOTE this code is not universal but suits my needs perfectly . What I noticed is that the AfterScroll event here is being triggered even if I have only One Record in the MasterQry , or even if I have non at all . I was really happy , I tested it multiple times and it delivered correct results.
I checked the TADOQuery.First and TADOQuery.Locate procedures and both had DoAfterScroll but it was not triggered with One Record or with No Record . ( the SlaveQry was left open in a undesired state )
I've googled a lot for this but was unable to find the reason .
My Question is : why does this work ? why does AfterScroll fires with One or No Record .
Thank you.
UPDATE
I can only reproduce this with Microsoft SQL . So in order to test this you need . Two Tables .
In MasterTable add two records ( ID , Text, Active )
1 First 1
2 Second 1
in the SlaveTable add two or more records ( ID,HeadID,Text )
1,1,First-1
2,1,First-2
3,2,Second-1
4,2,Second-2
Now drop on the Form one ADOConnection two ADOQueries .
in the MainQuery you have following text
Select * from MasterTable where Active=1
in the SlaveQuery you have following text
select * from SlaveTable where HeadID=:HeadID
on the MainQuery.BeforeOpen you have this :
MainQuery.AfterScroll:=nil;
on the MainQuery.AfterScroll you have this :
if SlaveQuery.Active then SlaveQuery.Close;
SlaveQuery.Parameters.ParamByName('HeadID').Value:=MainQueryID.Value;
SlaveQuery.Open;
on the MainQuery.AfterOpen you have this :
MainQuery.AfterScroll:=MainQueryAfterScroll;
Add a Button to this form :
Button1Click Event Contains following :
if MasterQuery.Active then MasterQuery.Close;
MasterQuery.Open;
So if you now attach a Grid to both Queries , you can see it is following perfectly .
Without closing the Program , go into the SQL Server Manager and run the following update statement :
update MasterTable set Active=0
Press the Button1 on the Form again :
The MasterQuery is Emtpy , the SlaveQuery was left in the Last Open State .
In order to fix this you need to alter the Button1Click as follows :
var AfterOpen,AfterScroll : TDataSetNotifyEvent;
begin
AfterOpen := AQuery.AfterOpen;
AfterScroll := AQuery.AfterScroll;
AQuery.AfterOpen:=nil;
AQuery.AfterScroll:=nil;
if AQuery.Active then AQuery.Close;
AQuery.Open;
AQuery.AfterOpen:=AfterOpen;
AQuery.AfterScroll:=AfterScroll;
if Assigned(AQuery.AfterScroll) then
AQuery.AfterScroll(AQuery);
end;
And now it works . I don't know why because MasterQuery.First should trigger DoAfterScroll but nothing Happens . It seems like Setting AfterScroll to nil and then back again somehow triggers AfterScroll even when it has 1 Record or is empty .