定位细节 TAdoQuery 后的异常

问题描述

我有一个 master 和一个 detail TAdoQuery,分别称为 FMasterFDetail。它们通过数据源 FMasterSource 连接。详细查询有一个参数,它会根据主查询自动填充和更新。

现在的问题是:在执行 FDetail.Locate(或实际上是 FDetail.Recordset.Clone)后,FMaster.Next 在尝试使用新参数重新查询 FDetail 时抛出异常:

  try
    FMaster.Open;
    FDetail.Open;
    FDetail.Locate('Id',2,[]);
    FMaster.Next; {<== throws Exception with ADO Errorcode 0x80040e05}
  finally
    FDetail.Close;
    FMaster.Close;
  end;

根据this List,错误代码0x80040e05 表示“对象已经打开”。

  • 问题似乎是,FDetail.Locate 创建了底层 Ado 记录集的克隆以供以后使用,并保存它。因此,我们可以将 Locate 替换为 recordsetClone := FDetail.Recordset.Clone(adLockReadOnly);(其中 uses Winapi.ADOInt)并得到相同的错误。
  • FMaster.Next 中,在设置 MasterId 的新参数后尝试重新查询 FDetail 会引发异常。这发生在 TCustomADODataSet.RefreshParams
  • 当您断开 Detail 与 Master 的连接时,一切正常。手动设置 FDetail 的参数效果很好。

我错过了什么? 这是 VCL 中的错误吗? 还是又一个奇怪的 ADO 错误?

源代码

我使用的是 Oracle 11g XE 和 Delphi 10.4 Sydney。

Oracle 表:

drop table Detail;
drop table Master;

create table Master (
  Id NUMBER(2) not null,constraint MasterPK primary key (Id)
);
create table Detail (
  Id       NUMBER(2) not null,MasterId NUMBER(2),constraint DetailPK primary key (Id),constraint DetailFK foreign key (MasterId) references Master(Id)
);
insert into Master values (1);
insert into Master values (2);
insert into Detail values (1,1);
insert into Detail values (2,1);
insert into Detail values (3,2);

德尔福代码:

procedure TForm1.Button1Click(Sender: TObject);
begin
  //Initializing...
  FConnection.Provider := 'OraOLEDB.Oracle.1';
  FConnection.ConnectionString := 'Provider=OraOLEDB.Oracle.1;Password=xxxx;Persist Security Info=True;User ID=TEST;Data Source=XE';
  FConnection.LoginPrompt := False;
  FConnection.KeepConnection := False;

  FMaster.Connection := FConnection;
  FMaster.SQL.Text := 'select Id from Master';
  FMaster.CursorLocation := clUseServer;
  FMaster.CursorType := ctStatic;

  FMasterSource.DataSet := FMaster;

  FDetail.Connection := FConnection;
  FDetail.DataSource := FMasterSource;
  FDetail.SQL.Add('select Id,MasterId from Detail where MasterId = :Id');
  FDetail.Parameters[0].DataType := ftInteger;
  FDetail.CursorLocation := clUseServer;

  //Do stuff
  try
    FMaster.Open;
    FDetail.Open;
    //FDetail.Locate('Id',[]);
    recordsetClone := FDetail.Recordset.Clone(adLockReadOnly);
    FMaster.Next; {<== throws Exception with ADO Errorcode 0x80040e05}
  finally
    FDetail.Close;
    FMaster.Close;
  end;
end;

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)