Delphi FDManager.DeleteConnectionDef不删除连接定义
我的应用程序有一个designtime TFDConnection,当它连接到另一个数据库类型时会被重用。 我还从池连接的设置派生一个池连接,并将其注册到FDManager.AddConnectionDef,以便在多线程处理时使用 第二次设置时,我无意中再次使用相同的ConnectionDefName调用AddConnectionDef。报告说: 该名称在ConnectionDefs列表中的其他连接定义中必须是唯一的,否则会引发异常 这种情况不会发生。没有引发任何异常,我只是得到了两个同名的connectiondf。 对于那些好奇的人:下一个代码块演示了这种行为。这不是我马上要解决的问题,因为我想得很好,然后我首先使用deleteConnectionDF删除旧的。 但事实证明,这也不起作用。请参阅第二段代码Delphi FDManager.DeleteConnectionDef不删除连接定义,delphi,database-connection,firedac,delphi-10.2-tokyo,Delphi,Database Connection,Firedac,Delphi 10.2 Tokyo,我的应用程序有一个designtime TFDConnection,当它连接到另一个数据库类型时会被重用。 我还从池连接的设置派生一个池连接,并将其注册到FDManager.AddConnectionDef,以便在多线程处理时使用 第二次设置时,我无意中再次使用相同的ConnectionDefName调用AddConnectionDef。报告说: 该名称在ConnectionDefs列表中的其他连接定义中必须是唯一的,否则会引发异常 这种情况不会发生。没有引发任何异常,我只是得到了两个同名的co
procedure TFrmFireDACConnectionNames.BtnBug1Click(Sender: TObject);
var
lParams: TStringList;
i,l : integer;
begin
lParams := TStringList.Create;
lParams.Add('User_Name=sysdba');
lParams.Add('Password=masterkey');
lParams.Add('database=D:\Testing\test.gdb');
lParams.Add('Server=localhost');
lParams.Add('Pooled=true');
lParams.Add('DriverID=FB');
FDManager.AddConnectionDef('FBPooled','FB',lParams);
lParams.Values['database'] := 'D:\Testing\test2.gdb';
FDManager.AddConnectionDef('FBPooled','FB',lParams);
// This shows the two identical ConnectionDefs (inspect lParams):
lParams.Clear;
l := FDManager.ConnectionDefs.Count;
for i := 0 to l-1 do
lParams.Add(FDManager.ConnectionDefs[i].Name);
// Contents on my machine:
// Access_Demo
// Access_Demo_Pooled
// DBDEMOS
// EMPOYEE
// MSSQL_Demo
// RBDemos
// SQLite_Demo
// SQLite_Demo_Pooled
// FBPooled <== Duplicates
// FBPooled
// To check that the two added have their respective Params, inspect lParams with breakpoints on the lines below:
lParams.Assign(FDManager.ConnectionDefs[l-1].Params);
// Contents on my machine:
// User_Name=sysdba
// Password=masterkey
// database=D:\Testing\test2.gdb
// Server=localhost
// Pooled=true
// DriverID=FB
// Name=FBPooled
lParams.Assign(FDManager.ConnectionDefs[l-2].Params);
// Contents on my machine:
// User_Name=sysdba
// Password=masterkey
// database=D:\Testing\test.gdb
// Server=localhost
// Pooled=true
// DriverID=FB
// Name=FBPooled
lParams.Free;
end;
那么这里会发生什么,我该如何解决
这是Delphi东京10.2.1
如果要运行此代码,请在表单上放置TFDPHYSFBRIVERLINK和TFDPHYSMSSQLDIVERLINK。我试着打电话。释放那些,但没有帮助
更正:运行代码不需要放置TFDPHYXXXDRIVERLINK组件。我之所以保留这句话,是因为它们的关联单元的存在对于AddConnectionDefinition bug是必不可少的,请参见批准的答案
问题已解决:FireDAC.Stan.Def.pas和FireDAC.Comp.Client.pas的修补程序可从该链接获得。如何删除连接定义?
删除循环的问题是由于访问迭代对象导致引用计数增加,从而阻止从定义集合中删除该对象。一般来说,我最好避免访问该收藏
顺便说一句,这种循环没有什么意义,因为删除方法需要的是名称,而不是索引,所以直接调用它基本上具有相同的效果:
FDManager.DeleteConnectionDef(lConnName);
这样做可以避免所提到的引用计数增加。但是继续读下去
如何防止连接定义名称重复?
但要从根本上解决你的问题。连接定义名称必须是唯一的,这是管理器应该注意的。不幸的是,你没有,因为你发现了一个bug。在修复之前,您只需在添加之前询问是否存在该名称的连接定义:
if not FDManager.IsConnectionDef('FBPooled') then
FDManager.AddConnectionDef('FBPooled', 'FB', Params)
else
raise EMyException.Create('Duplicate connection definition name!');
这样的代码可以作为您报告的问题的解决方法。我将试着描述出问题所在
防止连接定义名称重复有什么错?
对这个问题。嗯,这是一个很好的隐藏。只有当应用程序中包含物理驱动程序模块时,我才能重现该问题[1]。预期的例外情况:
[FireDAC][Stan][Def]-255。定义名称[FBPooled]重复
当应用程序中不包括物理驱动器模块时,正确升起。如果包含驱动程序模块,则不会引发异常,并将具有重复名称的连接定义添加到内部集合中
那么,当包含物理驱动程序模块时,为什么这样的代码不会像文档中所说的那样引发异常呢
FDManager.AddConnectionDef('DefName', 'FB', Params);
Params.Values['Database'] := 'C:\MyDatabase.db';
FDManager.AddConnectionDef('DefName', 'FB', Params);
TFDDefinition.ParamsChanged方法中存在对定义名称的重复检查,该方法反映了对连接定义参数的更改。听起来很奇怪,但是传递给AddConnectionDef方法的定义名称稍后会添加到name键下的定义参数中,引擎然后等待调用所提到的ParamsChanged方法的更改通知
AddConnectionDef方法中的定义设置如下所示:
Definition.Params.BeginUpdate; { ← triggers TFDDefinition.ParamsChanging }
try
Definition.Params.SetStrings(Params); { ← assigns the passed parameters }
Definition.Name := 'DefName'; { ← adds (or sets) the Name key value in Params }
Definition.Params.DriverID := 'FB'; { ← creates driver specific parameter instance }
finally
Definition.Params.EndUpdate; { ← triggers TFDDefinition.ParamsChanged }
end;
第一眼看上去不错。但是行设置Params.DriverID有一个小问题。它触发特定于驱动程序的参数实例的创建,例如替换原始参数集合的TFDPhysFBConnectionDefParams。没错,但是锁坏了
这也是在伪代码中发生的:
Definition.Params.BeginUpdate; { ← Definition.Params.FUpdateCount += 1 }
try
Definition.Params.Free;
Definition.Params := TDriverSpecificConnectionDefParams.Create;
finally
Definition.Params.EndUpdate; { ← Definition.Params.FUpdateCount == 0 }
end;
就这样。Params对象替换无法复制字符串列表的FUpdateCount值,该值必须为非零,才能在调用EndUpdate方法时触发OnChange事件
这就是为什么TFDDefinition.ParamsChanged方法不会从finally块触发的原因。如果您还记得我前面的一段话,那就是定义名称的重复检查所在的位置。因此,当包含驱动程序模块时,您可以添加重复项
在伪代码中解决此问题的可能方法是:
var
UpdateCount: Integer;
begin
Definition.Params.BeginUpdate; { ← Definition.Params.FUpdateCount == n }
try
UpdateCount := Definition.Params.UpdateCount; { ← store the update count }
Definition.Params.Free;
Definition.Params := TDriverSpecificConnectionDefParams.Create;
Definition.UpdateCount := UpdateCount; { ← set the update count for the new instance }
finally
Definition.Params.EndUpdate; { ← Definition.Params.FUpdateCount == n }
end;
end;
[1] 事实上,如果任何一个FireDAC.phy。驱动程序文件在您的使用列表中;通过在表单上放置TFDPhysDriverLink组件,可以自动包含这些内容。如何删除连接定义?
删除循环的问题是由于访问迭代对象导致引用计数增加,从而阻止从def中删除该对象
初始化集合。一般来说,我最好避免访问该收藏
顺便说一句,这种循环没有什么意义,因为删除方法需要的是名称,而不是索引,所以直接调用它基本上具有相同的效果:
FDManager.DeleteConnectionDef(lConnName);
这样做可以避免所提到的引用计数增加。但是继续读下去
如何防止连接定义名称重复?
但要从根本上解决你的问题。连接定义名称必须是唯一的,这是管理器应该注意的。不幸的是,你没有,因为你发现了一个bug。在修复之前,您只需在添加之前询问是否存在该名称的连接定义:
if not FDManager.IsConnectionDef('FBPooled') then
FDManager.AddConnectionDef('FBPooled', 'FB', Params)
else
raise EMyException.Create('Duplicate connection definition name!');
这样的代码可以作为您报告的问题的解决方法。我将试着描述出问题所在
防止连接定义名称重复有什么错?
对这个问题。嗯,这是一个很好的隐藏。只有当应用程序中包含物理驱动程序模块时,我才能重现该问题[1]。预期的例外情况:
[FireDAC][Stan][Def]-255。定义名称[FBPooled]重复
当应用程序中不包括物理驱动器模块时,正确升起。如果包含驱动程序模块,则不会引发异常,并将具有重复名称的连接定义添加到内部集合中
那么,当包含物理驱动程序模块时,为什么这样的代码不会像文档中所说的那样引发异常呢
FDManager.AddConnectionDef('DefName', 'FB', Params);
Params.Values['Database'] := 'C:\MyDatabase.db';
FDManager.AddConnectionDef('DefName', 'FB', Params);
TFDDefinition.ParamsChanged方法中存在对定义名称的重复检查,该方法反映了对连接定义参数的更改。听起来很奇怪,但是传递给AddConnectionDef方法的定义名称稍后会添加到name键下的定义参数中,引擎然后等待调用所提到的ParamsChanged方法的更改通知
AddConnectionDef方法中的定义设置如下所示:
Definition.Params.BeginUpdate; { ← triggers TFDDefinition.ParamsChanging }
try
Definition.Params.SetStrings(Params); { ← assigns the passed parameters }
Definition.Name := 'DefName'; { ← adds (or sets) the Name key value in Params }
Definition.Params.DriverID := 'FB'; { ← creates driver specific parameter instance }
finally
Definition.Params.EndUpdate; { ← triggers TFDDefinition.ParamsChanged }
end;
第一眼看上去不错。但是行设置Params.DriverID有一个小问题。它触发特定于驱动程序的参数实例的创建,例如替换原始参数集合的TFDPhysFBConnectionDefParams。没错,但是锁坏了
这也是在伪代码中发生的:
Definition.Params.BeginUpdate; { ← Definition.Params.FUpdateCount += 1 }
try
Definition.Params.Free;
Definition.Params := TDriverSpecificConnectionDefParams.Create;
finally
Definition.Params.EndUpdate; { ← Definition.Params.FUpdateCount == 0 }
end;
就这样。Params对象替换无法复制字符串列表的FUpdateCount值,该值必须为非零,才能在调用EndUpdate方法时触发OnChange事件
这就是为什么TFDDefinition.ParamsChanged方法不会从finally块触发的原因。如果您还记得我前面的一段话,那就是定义名称的重复检查所在的位置。因此,当包含驱动程序模块时,您可以添加重复项
在伪代码中解决此问题的可能方法是:
var
UpdateCount: Integer;
begin
Definition.Params.BeginUpdate; { ← Definition.Params.FUpdateCount == n }
try
UpdateCount := Definition.Params.UpdateCount; { ← store the update count }
Definition.Params.Free;
Definition.Params := TDriverSpecificConnectionDefParams.Create;
Definition.UpdateCount := UpdateCount; { ← set the update count for the new instance }
finally
Definition.Params.EndUpdate; { ← Definition.Params.FUpdateCount == n }
end;
end;
[1] 事实上,如果任何一个FireDAC.phy。驱动程序文件在您的使用列表中;通过在表单上放置TFDPhysDriverLink组件,可以自动包含这些内容。这是一些检测工作!当AddConnectionDef进入InterfaceIdStandDefinitions时,我已停止跟踪它;-我错过了FireDAC新出现的IsConnectionDef的存在。顺便说一句,我在你的答案中编辑了一个脚注。@Jan,我花了一段时间才找到它。我怀疑接口引用,在搜索不调用ParamsChanged方法的原因时,完全忽略了在其自身更新锁中的对象替换。谢谢你的脚注;我只是把它格式化,使之与文章的其余部分相适应。你的第一段话太真实了!!应用IsConnectionDef“fix”后,我的测试程序运行良好,但我的实际程序在重复连接定义名称方面一直存在问题。原因:一个简单的事实是我正在阅读connectiondfs[]。查看是否一切正常!真是浪费时间。我现在在RSP-19107中加上这一点,我认为它太详细了,不能这么说。@Victoria:又是一个一流的答案+我很高兴有人能找出FDac的复杂之处。那是一些侦探工作!当AddConnectionDef进入InterfaceIdStandDefinitions时,我已停止跟踪它;-我错过了FireDAC新出现的IsConnectionDef的存在。顺便说一句,我在你的答案中编辑了一个脚注。@Jan,我花了一段时间才找到它。我怀疑接口引用,在搜索不调用ParamsChanged方法的原因时,完全忽略了在其自身更新锁中的对象替换。谢谢你的脚注;我只是把它格式化,使之与文章的其余部分相适应。你的第一段话太真实了!!应用IsConnectionDef“fix”后,我的测试程序运行良好,但我的实际程序在重复连接定义名称方面一直存在问题。原因:一个简单的事实是我正在阅读connectiondfs[]。查看是否一切正常!真是浪费时间。我现在在RSP-19107中加上这一点,我认为它太详细了,不能这么说。@Victoria:又是一个一流的答案+1我 我很高兴有人能理解FDac的复杂性。