ADOQuery AfterScroll未被一个记录/没有记录触发

时间:2019-02-14 06:39:22

标签: delphi tadoquery

我在表格上有一个MasterQry和一个SlaveQry。 MasterQry是这样的:

select * from Header where Active = 1

在AfterScroll事件中,我有以下内容:

select * from Slave where HeadID=:Header.ID

现在,如果我愿意:

if MasterQry.Active then MasterQry.Close;
MasterQry.Open;

如果我有一个以上的记录,这将完美地工作,但是如果我只有一个记录,则将无法工作。

即使我MasterQry.First;也没事。

如果我尝试MasterQry.AfterScroll(MasterQry),则会遇到访问冲突。

我正在重构代码,并试图使其更紧凑,因为我做了很多“打开关闭定位ID”(需要刷新数据以获取实际状态,是否被锁定等),并且这样做: / p>

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;

请注意,此代码不是通用代码,但非常适合我的需求。我注意到的是,即使MasterQry中只有一个记录,或者根本没有,也将触发AfterScroll事件。我真的很高兴,我对其进行了多次测试,并给出了正确的结果。

我检查了TADOQuery.First和TADOQuery.Locate过程,它们都具有DoAfterScroll,但是没有通过“一个记录”或“没有记录”来触发。 (SlaveQry处于打开状态,处于不希望的状态)

为此我做了很多搜索,但找不到原因。

我的问题是:为什么这样做有效?为什么AfterScroll触发一条或一条记录。

谢谢。

更新

我只能使用Microsoft SQL复制它。因此,为了测试这一点,您需要。两张桌子。

MasterTable 中添加两条记录(ID,Text,Active)

1首1

2秒1

从表中添加两个或多个记录(ID,HeadID,文本)

1,1,First-1

2,1,First-2

3,2,Second-1

4,2,Second-2

现在将两个 ADOQueries 放在窗体 ADOConnection 上。

MainQuery 中,您有以下文本

Select * from MasterTable where Active=1

SlaveQuery 中,您有以下文字

select * from SlaveTable where HeadID=:HeadID

MainQuery.BeforeOpen 上,您具有以下功能:

MainQuery.AfterScroll:=nil;

MainQuery.AfterScroll 上,您具有以下功能:

if SlaveQuery.Active then SlaveQuery.Close;
SlaveQuery.Parameters.ParamByName('HeadID').Value:=MainQueryID.Value;
SlaveQuery.Open;

MainQuery.AfterOpen 上,您具有以下功能:

MainQuery.AfterScroll:=MainQueryAfterScroll;

在此表单中添加按钮

Button1Click事件包含以下内容:

if MasterQuery.Active then MasterQuery.Close;
MasterQuery.Open;

因此,如果您现在将网格附加到两个查询,则可以看到它完美地遵循了。

在不关闭程序的情况下,进入SQL Server管理器并运行以下更新语句:

update MasterTable set Active=0

再次在表单上按Button1:

MasterQuery是Emtpy,SlaveQuery处于上次打开状态。

要解决此问题,您需要按以下方式更改Button1Click:

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;

现在它可以工作了。我不知道为什么,因为MasterQuery.First应该触发DoAfterScroll但什么都不会发生。 似乎将AfterScroll设置为nil,然后再次返回就可以触发AfterScroll,即使它具有1条Record或为空。

1 个答案:

答案 0 :(得分:4)

正如我在评论中所说,RefreshQuery中的大多数代码都不是必需的, 因为链接Master-> Detail数据集应该“正常”。实际上,您的RefreshQuery完全没有必要。

我仅通过删除组件就根据您的主表和从表创建了一个最小的项目 从面板上进行布线,然后仅在下面的Form1.FormCreate中添加代码。的 从属网格的内容正确跟踪主网格,包括以下情况: 没有匹配的从站记录,即从站网格显示为空。请注意,没有任何需要的数据事件,即没有AfterScroll也没有Locate等呼叫。

  type
    TForm1 = class(TForm)
      dsMaster: TDataSource;
      DBGrid1: TDBGrid;
      DBNavigator1: TDBNavigator;
      DBGrid2: TDBGrid;
      DataSource2: TDataSource;
      DBNavigator2: TDBNavigator;
      ADOConnection1: TADOConnection;
      qMaster: TADOQuery;
      qSlave: TADOQuery;
      qSlaveID: TIntegerField;
      qSlaveHeaderID: TIntegerField;
      qSlaveAText: TWideStringField;
      procedure FormCreate(Sender: TObject);
    public
    end;

  [...]

  procedure TForm1.FormCreate(Sender: TObject);
  begin
    qMaster.SQL.Text := 'select * from mastertable';

    qSlave.DataSource := dsMaster;
    qSlave.SQL.Text := 'select * from slavetable where headerid = :id';
    //  NOTE: because the DataSource property of qSlave is set to dsMaster,
    //  the ` = :id` tells the Ado run-time code to get the value of the
    //  ID field in the qMaster table.

    qMaster.Open;
    qSlave.Open;
  end;

如果要在其他用户更改记录的情况下刷新主表或从表,则可以执行以下操作:

procedure TForm1.Button1Click(Sender: TObject);
begin
  qMaster.Refresh;
end;

,但是请注意,该表需要在Sql Server上正确设置。只要将ID字段设置为主键,并且/或者在服务器上设置了唯一索引,对Refresh的调用应该可以正常工作,但是如果没有,则会出现错误并显示一条消息,提示“密钥信息不足以进行更新或刷新”。您当然可以在计时器上进行刷新(但不要过于频繁地调用它,即每隔几秒钟不止一次)。