因此,我从第三方库中收到一个错误,“无法删除表,因为它已被另一个数据集打开”,并且我很难找到正在使用它的数据集,因为我们要花很多时间数据集分配。我已经创建了一个测试应用程序,要获得此错误的唯一方法是让对象具有分配给数据集的属性。我的问题是:是否有什么好的方法来查找数据集的地址是否已分配给另一个变量的属性?
例如,如果我有:
ObjX: TDateset;
ObjY: TAdoQuery;
procedure Test(TestDS: TDataset);
begin
ObjY.Dataset := TestDS;
end
procedure Form1.FormCreate(Sender: TObject);
begin
Test(ObjX);
end
如果由于某种原因我不知道ObjY存在或没有它的data属性设置,是否仍然可以只使用ObjX以及也许其他调试工具来发现ObjY具有分配给ObjX的属性? / p>
答案 0 :(得分:1)
更新我已对其进行了更新,以包括另一种搜索方式 引用给定表名称的组件,请参见下文。
下面的示例项目显示了如何在应用程序中捕获活动对象
对象并检查其中是否有一个引用(按名称)
给定的表。在此示例中,通过单击按钮触发了检查,但是显然
您的情况下,您会在问题发生时触发它。任何与
TableRef
值记录到TMemo。它没有涵盖所有可能性,例如无所有者的组件,但应为您提供一般的想法。
您将看到,它取决于类型转换组件到特定的TDataSet后代
然后检查它们可能相关的属性。就我而言,我正在寻找
在许多TAdoDataset类型中对名为“ authors”的表的引用,特别是
TAdoQuery和TAdoTable。你会
必须使CheckComponentForTableRef
中的代码适应特定的数据集类型
您正在使用。
代码:
procedure TForm1.CheckComponentForTableRef(AComponent: TComponent;
const TableRef: String);
var
i : Integer;
begin
if AComponent is TAdoQuery then begin
if Pos(LowerCase(TableRef), AComponent.Name) > 0 then
LogReference(AComponent, 'ComponentName', TableRef);
if Pos(LowerCase(TableRef), TAdoQuery(AComponent).Sql.Text) > 0 then
LogReference(AComponent, 'SqlText', TableRef);
end;
if AComponent is TAdoTable then begin
if Pos(LowerCase(TableRef), TAdoTable(AComponent).TableName) > 0 then
LogReference(AComponent, 'TableName', TableRef);
end;
// the following recursively examines AComponent's sub-components
for i := 0 to AComponent.ComponentCount - 1 do
CheckComponentForTableRef(AComponent.Components[i], TableRef);
end;
procedure TForm1.FindTableRefs(const TableRef: String);
var
i : Integer;
begin
for i := 0 to Application.ComponentCount - 1 do begin
// The Application object's Components include the forms
// and datamodules created with it as Owner.
CheckComponentForTableRef(Application.Components[i], TableRef);
end;
end;
procedure TForm1.LogReference(AComponent: TComponent;
const AProperty : String;
const TableRef: String);
var
S : String;
begin
S := AComponent.Name;
if AComponent.Owner <> Nil then
S := AComponent.Owner.Name + ':' + S;
Memo1.Lines.Add(Format('Component: %s, Property: %s, TableRef: %s', [S, AProperty, TableRef]));
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
FindTableRefs('authors');
end;
更新
上述方法的明显缺点是CheckComponentForTableRef
该方法需要对项目中使用的特定TDataSet后代进行类型转换。
下面显示了一种替代方法,该方法涉及检查字符串表示形式
项目组成部分。这样就无需自定义CheckComponentForTableRef
因此,下面的示例可以按原样使用。唯一明显的缺点是
检查的字符串表示形式是组件的已发布属性;然而
因为对象检查器对此进行操作,并且通常是建立数据库访问的方式,
这种劣势可能比实际更具理论性。
function TForm1.ComponentToString(AComponent : TComponent) : String;
var
SS : TStringStream;
MS : TMemoryStream;
Writer : TWriter;
begin
// Note: There may be a more direct way of doing the following, without
// needing the TMemoryStream, MS
SS := TStringStream.Create('');
MS := TMemoryStream.Create;
Writer := TWriter.Create(MS, 4096);
try
Writer.Root := Self;
Writer.WriteSignature;
Writer.WriteComponent(AComponent);
Writer.FlushBuffer;
MS.Position := 0;
ObjectBinaryToText(MS, SS);
Result := SS.DataString;
finally
Writer.Free;
MS.Free;
SS.Free;
end;
end;
procedure TForm1.SearchForString(const TableRef : String);
var
i : Integer;
procedure SearchComponentForString(AComponent : TComponent; const TableRef : String);
var
i : Integer;
S : String;
begin
// the following line prevents the contents of Memo1, which is
// used for logging, being searched
if AComponent = Memo1 then exit;
S := ComponentToString(AComponent);
if Pos(LowerCase(TableRef), LowerCase(S)) > 0 then begin
LogReference(AComponent, S, TableRef);
Exit; // TableRef found, so don't recurse into sub-components
end;
for i := 0 to AComponent.ComponentCount - 1 do
SearchComponentForString(AComponent.Components[i], TableRef);
end;
begin
for i := 0 to Application.ComponentCount - 1 do
SearchComponentForString(Application.Components[i], TableRef);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SearchForString('authors');
end;