Delphi:全局更改ADO命令超时

时间:2011-09-19 14:13:07

标签: delphi timeout ado

我们有一个巨大的Delphi 2005应用程序,其中有大量的ADO组件(TADODataset,TADOStoredPRoc,TADOCommand ...)在表单的hundreads上传播。所有这些都连接到SINGLE TADOConnection。

这些组件中的大多数将其CommandTimeout属性设置为默认值(30秒),但有一些设置为5分钟(300秒),有些设置为永不超时(0秒)。

我希望能够全局更改应用程序范围内所有ADO组件的此设置。我更喜欢在运行时以编程方式执行此操作,以便我可以根据需要调整每次安装的超时。

我希望在创建/附加ADO组件时可以在连接上找到全局事件,在那里我可以调整命令时间,或者破解我在组件本身中注入代码的方式,但是空白了。 / p>

我不想创建后代,因为我必须搜索/替换所有组件,如果我忘记使用后代而不是常规ADO组件,我的超时将不会跟随应用程序的其余部分。

任何人都知道我们该如何做到这一点?

5 个答案:

答案 0 :(得分:3)

如果所有ADO组件都放在表单上,​​则可以使用Screen.Forms和Screen.FormCount属性迭代所有表单。对于每个表单迭代其ComponentCount / Components属性并检查TADOCommand,TADODataSet,TADOQuery,TADOStoredProc和TADOTable。然后您可以根据需要设置超时。当然,如果您动态创建表单,则必须单独考虑这一点。

以下代码可能会为您提供指导。

procedure SetADOTimeout(ATimeout: Integer);
var
  cmp: TComponent;
  frm: TForm;
  I: Integer;
  J: Integer;
begin
  for I := 0 to Screen.FormCount - 1 do begin
    frm := Screen.Forms[I];
    for J := 0 to frm.ComponentCount - 1 do begin
      cmp := frm.Components[J];
      if cmp is TADOCommand then
        TADOCommand(cmp).CommandTimeout := ATimeout
      else if cmp is TADODataSet then
        TADODataSet(cmp).CommandTimeout := ATimeout
      else if cmp is TADOQuery then
        TADOQuery(cmp).CommandTimeout := ATimeout
      else if cmp is TADOStoredProc then
        TADOStoredProc(cmp).CommandTimeout := ATimeout
      else if cmp is TADOTable then
        TADOTable(cmp).CommandTimeout := ATimeout;
    end;
  end;
end;

答案 1 :(得分:1)

向所有阿根廷解决方案致以问候!

只需为您拥有的TADOConnection定义OnWillExecute事件处理程序,然后编写以下代码:

type
  TCustomADODataSetAccess = class(TCustomADODataSet);

procedure TYourDataModule.ADOConnectionWillExecute(...);
var
  i: Integer;
begin
  for i := 0 to ADOConnection.DataSetCount - 1 do
    TCustomADODataSetAccess(ADOConnection.DataSets[i]).CommandTimeout := Connection.CommandTimeout;
end;

这将为使用ADO连接的任何查询/表/存储过程设置命令超时。

答案 2 :(得分:0)

根据文档,您可以使用CommandCountCommands找到附加到TADOConnection的所有打开的组件。

您的问题很可能是动态创建的表单。在创建表单时,您需要找到要挂钩的“东西”并检查该表单上的ADO组件。

如果您的表单来自自定义表单类,则可以在表单的constructorOnCreate事件中执行此操作。

如果没有,您可以查看TApplicationEvents并使用TApplication's OnIdle事件。

答案 3 :(得分:0)

由于在TCustomADODataset类中引入了CommandTimeout,您可以迭代每个表单/数据模块,找到TCustomADODataset及其后代(ADODataset,ADOTable,ADOQuery)然后设置属性。

procedure SetADOCommandTimeOut(aTimeOut: integer);
var
  i, j: integer;
begin
  for i:= 0 to Screen.FormCount-1 do
  begin
    for j:= 0 to Forms[i].ComponentCount-1 do
      if Forms[i].Components[j] is TCustomADODataset then
        TCustomADODataset1(Forms[i].Components[j]).CommandTimeOut:= aTimeOut;
  end;

  for i:= 0 to Screen.DataModuleCount-1 do
  begin
    for j:= 0 to Datamodules[i].ComponentCount-1 do
      if Datamodules[i].Components[j] is TCustomADODataset then
        TCustomADODataset1(Datamodules[i].Components[j]).CommandTimeOut:= aTimeOut;
  end;
end;

注意:TCustomADODataset1正好是TCustomADODataset,只有它具有已发布的CommandTimeOut属性:

TCustomADODataset1 = class(TCustomADODataset)
published
  property CommandTimeOut;
end;

但它仅适用于已创建的表单/数据模块。如果动态创建表单/数据模块,则必须在创建新表单/数据模块时应用它。 一种方法是通过覆盖Mainform中的Notification,检查一个新的form / datamodule创建,但这有点棘手,因为在创建时,所有组件都没有创建。你通过使用计时器延迟一段时间来欺骗它(我不知道更优雅的方式 - 只是为了表明这个想法)

Procedure TMainForm.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;
  if (Operation = opInsert) and (
     ((AComponent is TForm) and not (aComponent is TMainForm)) // exclude MainForm 
     or (AComponent is TDataModule)
     ) then
  begin
    Timer1.Interval:= 2000; // 2 seconds ?
    Timer1.Enabled:= True;
  end;
end;

Procedure TMainForm.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled:= False;
  SetADOCommandTimeOut(MyTimeOut);
end;

答案 4 :(得分:0)

您是否创建了数据模块层次结构?如果是这样,你可以在你的族长表格(所有其他数据模块都继承)上使用像Uwe的答案这样的代码。