我们有一个巨大的Delphi 2005应用程序与大量的ADO组件(TADODataset, TADOStoredPRoc, TADOCommand…)分布在数百个表单。所有这些都连接到一个TADOConnection。
大多数组件都将CommandTimeout属性设置为默认值(30s),但少数组件将其设置为5分钟(300s),有些组件将其设置为永不超时(0s)。
我希望能够全局地更改所有ADO组件在应用程序范围内的设置。我更喜欢在运行时通过编程来实现,这样我就可以在每个安装的基础上调整超时,如果我需要的话
我希望我能在连接上找到一个全局事件,当一个ADO组件被创建/附加,在那里我可以调整命令超时,或者hack我的方式注入我的代码在组件本身,但出现空白。
我不想创建后代,因为我将不得不搜索/替换所有组件,如果我忘记使用后代而不是常规的ADO组件,我的超时将跟随应用程序的其余部分。
有谁知道怎么做吗?
如果所有ADO组件都放置在一个表单上,则可以使用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;
向所有阿根廷解决方案致敬!
为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连接的任何查询/表/存储过程设置命令超时时间。
根据文档,您可以使用CommandCount
和Commands
来定位连接到TADOConnection
的所有打开组件。
您的问题可能是动态创建表单。当创建表单时,您需要找到"某些东西"来挂钩,并检查该表单上的ADO组件。
如果您的表单来自自定义表单类,您可以在表单的constructor
或OnCreate
事件中执行此操作。
如果没有,您可以查看TApplicationEvents
并使用TApplication's OnIdle
事件。
因为CommandTimeout是在TCustomADODataset类中引入的,你可以迭代每个表单/数据模块,找到一个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,检查表单/数据模块的新创建,但这有点棘手,因为在创建时,还没有创建所有组件。你可以通过使用计时器延迟它一段时间来欺骗它(我不知道一个更优雅的方法-只是为了展示这个想法)
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;
您创建了数据模块层次结构?如果是这样,您可以在父级表单(所有其他数据模块都继承)上使用类似Uwe的答案的代码。