【发布时间】:2017-02-28 11:26:38
【问题描述】:
忽略它使用 Aurelius 框架的事实,这个问题更多的是关于我需要如何重新调整代码以使通用构造函数注入对这两种类型都有效:
和
还要忽略子对象在同一个单元中的事实,我通常会将它们放在自己的单元中,但这只是为了更容易在问题中发布。
我正在尝试使用工厂方法模式来确定它应该在运行时建立什么类型的连接,具体取决于我实例化的对象。 目前它正在硬编码它在创建时期望的链接类型。
在示例中,我想传入一个 TModelDatabaseLink,但想在运行时决定它可能是什么类型的数据库连接,或者数据库连接是否来自文件。 是的,我知道我可以取消注释 FFilename 并使用它来保存文件名版本,但我总是有兴趣了解更多信息。
unit Model.Database.Connection;
interface
uses
System.Classes,
Data.DB,
Aurelius.Drivers.Interfaces,
Aurelius.Engine.DatabaseManager;
type
TModelDatabaseLink<T> = class
private
//FFilename: string;
FConnection: T;
FOwnsConnection: boolean;
OwnedComponent: TComponent;
end;
TModelDatabaseConnection = class abstract
private
FDatabaseLink: TModelDatabaseLink<TCustomConnection>;
FDatabaseManager: TDatabaseManager;
FConnection: IDBConnection;
function CreateConnection: IDBConnection; virtual; abstract;
procedure CreateDatabaseManager;
public
constructor Create(ADatabaseLink: TModelDatabaseLink<TCustomConnection>);
destructor Destroy; override;
property Connection: IDBConnection read FConnection;
end;
TSQLLiteConnection = class(TModelDatabaseConnection)
private
function CreateConnection: IDBConnection; override;
end;
TFireDacConnection = class(TModelDatabaseConnection)
private
function CreateConnection: IDBConnection; override;
end;
implementation
uses
System.SysUtils,
Aurelius.Drivers.Base,
Aurelius.Drivers.SQLite,
Aurelius.Drivers.FireDac,
FireDAC.Stan.Intf, FireDAC.Stan.Option,
FireDAC.Stan.Error, FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def,
FireDAC.Stan.Pool, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.VCLUI.Wait,
FireDAC.Comp.Client;
{ TModelDatabaseConnection }
constructor TModelDatabaseConnection.Create(ADatabaseLink: TModelDatabaseLink<TCustomConnection>);
begin
FDatabaseLink := ADatabaseLink;
FConnection := CreateConnection;
if Assigned(FConnection) then
CreateDatabaseManager
else
raise Exception.Create('Failed to open database');
end;
procedure TModelDatabaseConnection.CreateDatabaseManager;
begin
FDatabaseManager := TDatabaseManager.Create(FConnection);
end;
destructor TModelDatabaseConnection.Destroy;
begin
FDatabaseManager.Free;
FDatabaseLink.Free;
inherited Destroy;
end;
{ TSQLLiteConnection }
function TSQLLiteConnection.CreateConnection: IDBConnection;
var
LFilename: String;
LAdapter: TSQLiteNativeConnectionAdapter;
begin
//LFileName := FDatabaseLink.FConnection; << needs to be type string
LAdapter := TSQLiteNativeConnectionAdapter.Create(LFilename);
LAdapter.DisableForeignKeys;
Result := LAdapter;
end;
{ TFireDacConnection }
function TFireDacConnection.CreateConnection: IDBConnection;
var
LAdapter: TFireDacConnectionAdapter;
begin
if Assigned(FDatabaseLink.OwnedComponent) then
LAdapter := TFireDacConnectionAdapter.Create(FDatabaseLink.FConnection as TFDConnection, FDatabaseLink.OwnedComponent)
else
LAdapter := TFireDacConnectionAdapter.Create(FDatabaseLink.FConnection as TFDConnection, FDatabaseLink.FOwnsConnection);
Result := LAdapter;
end;
end.
如果可能的话,我想做的另一件事是更改两个创作:
LAdapter := TSQLiteNativeConnectionAdapter.Create(LFilename)
LAdapter := TFireDacConnectionAdapter.Create(FDatabaseLink.FConnection as TFDConnection, FDatabaseLink.OwnedComponent)
在父级 TModelDatabaseConnection 中使用抽象的“GetAdapterClass”类型函数,并在子级中声明适配器的类以执行以下操作:
LAdapter := GetAdapterClass.Create...
适配器声明的一个例子是
TFireDacConnectionAdapter = class(TDriverConnectionAdapter<TFDConnection>, IDBConnection)
【问题讨论】:
-
您使用的是 Spring.Persistence 适配器吗?因为这段代码对我来说很熟悉。如果是这样,请查看 Spring.Persistence.Core.ConnectionFactory.pas 如何为适配的连接注入不同的 ctor 参数。
-
嘿斯特凡。老实说,这些实际上是来自 TMS Aurelius 框架的那些。不过,我也会看看 Spring 单元,因为我的 PC 上也有它们,看看它是否能给我更多线索。
-
嗨斯特凡。在 Spring.Persistence.Adapters.SQLite 中,您指定必须传入 TSQLiteDatabase 而不仅仅是文件名。我可以在 Spring 代码中找到的唯一一个是 ..\Marshmallow\External\SQLite3 下的那个。这是“官方”春季版吗?
-
适配器总是让他们的适配器通过。但是由于它们的实现,被适配者的 ctor 参数可能会有所不同。这是由知道如何解析不同参数的 DI 容器或我在上一条评论中提到的单元处理的。至于 SQLite3 单元 - 它们修复了一些错误,但它们不是官方的,因为我们不为它们提供任何支持、维护或责任。
标签: delphi dependency-injection delphi-10-seattle delphi-10.1-berlin