开发者

Delphi : Globally change ADO command timeout

开发者 https://www.devze.com 2023-04-06 09:39 出处:网络
We have a HUGE Delphi 2005 application with LOTS of ADO components (TADODataset, TADOStoredPRoc, TADOCommand...) spread on hundreads of forms. All of them are connected to a SINGLE TADOConnection.

We have a HUGE Delphi 2005 application with LOTS of ADO components (TADODataset, TADOStoredPRoc, TADOCommand...) spread on hundreads of forms. All of them are connected to a SINGLE TADOConnection.

Most of these components have their CommandTimeout property set to the default (30s) but a few have it set to 5 minutes (300s) and some are set to never timeout (0s).

I'd like to be able to globally change this setting for all ADO components application-wide. I'd prefer to do it programmatically at runtime so that I could tweak the timeouts on a per-installation basis if I need to.

I was hoping I could find a global event on the connection when an ADO component is created/attached, where I could tweak the commandtimeout, or hack my way into injecting my code in the components themselves, but came up blank.

I don't want to create decendants because I'll ha开发者_如何学运维ve to search/replace trought all the components, and if I ever forget to use the descendants instead of the regular ADO components my timeout wont follow the rest of the application.

Anybody has an idea how we could do this ?


If all of you ADO components are placed on a form, you can iterate over all forms using the Screen.Forms and Screen.FormCount properties. For each form iterate over its ComponentCount/Components property and check for TADOCommand, TADODataSet, TADOQuery, TADOStoredProc and TADOTable. Then you can set the timeout as you wish. Of course, if you create forms dynamically you have to take this into account separately.

The following code may guide you.

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;


Greetings to all Argentinian solutions!

Just define the OnWillExecute event handler for the TADOConnection you have and write following code:

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;

This will set the command timeout for any query/table/stored procedure which uses your ADO connection.


According to the documentation, you can use CommandCount and Commands to locate all the open components attached to your TADOConnection.

Your problem is likely to be dynamically created forms. You'll need to find "something" to hook when a form is created and check for ADO components on that form.

If your forms descend from a custom form class, you could do this in the form's constructor or OnCreate event.

If not, you could look at TApplicationEvents and using the TApplication's OnIdle event.


Since CommandTimeout is introduced in the TCustomADODataset class, you can iterate for each form/datamodule, find a TCustomADODataset and it's descendants (ADODataset, ADOTable, ADOQuery) then set the Property.

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;

Note: TCustomADODataset1 is exactly TCustomADODataset, only it has a published CommandTimeOut property :

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

But it's only applied to forms/datamodules which are already created. If you create your forms/datamodules dynamically, then you must apply it whenever a new form/datamodule is created. One way to do it is by override Notification in your Mainform, checking for a new a creation of form/datamodule, but this a little bit tricky since at the the creation time, all the components are not created yet. You trick it by delay it for a while using a timer (I don't know a more elegant way - just to show the idea)

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;


You create datamodule hierarchies? If so, you can use code like Uwe's answer on your patriarch form (which all other datamodules inherit).

0

精彩评论

暂无评论...
验证码 换一张
取 消