-1

忽略这个使用Aurelius框架的事实,这个问题更多的是关于如何重新调整代码以使这两种类型的泛型构造函数注入都可以工作:
<字符串>

< TCustomConnection>
还忽略了一个事实,孩子的对象是在同一个单位,我一般把他们自己,但这恰恰使得它更容易在发帖提问。什么是构造这个通用对象创建的正确方法

我想使用工厂方法模式来确定它应该在运行时进行什么类型的连接,具体取决于我实例化的对象。 目前,它正在对创建期望的链接类型进行硬编码。

在这个例子中,我想传递一个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) 
+0

难道你正在使用Spring.Persistence适配器吗?因为这段代码对我来说看起来很熟悉。如果是这样,请查看Spring.Persistence.Core.ConnectionFactory.pas注入适配连接的不同ctor参数的方式。 –

+0

嘿Stefan。实际上,这些实际上是TMS Aurelius框架中的那些。不过,我会看看Spring的单元,就像我在PC上看到的那样,看看它是否给了我更多的线索。 – mikelittlewood

+0

嗨Stefan。在Spring.Persistence.Adapters.SQLite中,您指定必须传递TSQLiteDatabase而不仅仅是文件名。在Spring代码中唯一可以找到的是.. \ Marshmallow \ External \ SQLite3。这是一个“官方”春季吗? – mikelittlewood

回答

0

我之前做过这个,当时我写了一个抽象层,以防我需要在我的应用程序中替换Aurelius。我认为处理你想要做的最好的方法是使用接口。

我在这里复制我的代码的某些部分与调整:

TServerType = (stLocal, stFireDac); 

    IDatabase = interface 
    function getDatabaseType: TServerType; 
    property DatabaseType: TServerType read getDatabaseType; 
    end; 

    IAurelius = interface (IDatabase) 
    ['{990BB776-2E70-4140-B118-BEFF61FDBDAF}'] 
    function getDatabaseConnection: IDBConnection; 
    function getDatabaseManager: TDatabaseManager; 
    property DatabaseConnection: IDBConnection read getDatabaseConnection; 
    property DatabaseManager: TDatabaseManager read getDatabaseManager; 
    end; 

    IAureliusLocal = interface (IAurelius) 
    ['{9F705CC4-6E3B-4706-B54A-F0649CED3A8D}'] 
    function getDatabasePath: string; 
    property DatabasePath: string read getDatabasePath; 
    end; 

    IAureliusFireDac = interface (IAurelius) 
    // I use this for a memory database but the logic is the same for FireDAC. You need to add the required properties 
    end; 

    TAurelius = class (TInterfacedObject, IAurelius) 
    private 
    fServerType: TServerType; 
    fDatabaseConnection: IDBConnection; 
    fDatabaseManager: TDatabaseManager; 
    function getDatabaseConnection: IDBConnection; 
    function getDatabaseManager: TDatabaseManager; 
    public 
    constructor Create (const serverType: TServerType); 
    end; 

    TAureliusLocal = class (TAurelius, IAureliusLocal) 
    private 
    fDatabasePath: string; 
    function getDatabasePath: string; 
    public 
    constructor Create (const databasePath: string); 
    end; 

    TAureliusFireDac = class (TAurelius, IAureliusFireDac) 
    public 
    constructor Create (const aConnection: TFDConenction); <-- or whatever parameters you need here to initalise the FireDac connection 
    end; 

我要跳过的代码对所有的getXXX功能在这里。

的构造器是这些:

constructor TAurelius.Create(const serverType: TServerType); 
begin 
    inherited Create; 
    fServerType:=serverType; 
end; 

constructor TAureliusLocal.Create (const databasePath: string); 
const 
    databaseFilename = 'test.sqlite'; 
begin 
    inherited Create(stLocal); 
    fDatabasePath:=Trim(databasePath); 
    try 
    fDatabaseConnection:= 
    TSQLiteNativeConnectionAdapter.Create(
     TPath.Combine(fDatabasePath, databaseFilename)); 
    except 
    raise Exception.Create('stLocal database can''t be created'); 
    end; 
end; 

constructor TAureliusFireDac.Create (const aConnection: TFDConenction); 
begin 
    inherited Create(stFireDac); 
    // <-- here you initialise the connection like before but for FireDac 
end; 

现在,当您要创建您使用以下功能的奥勒留数据库:

function createAureliusDatabase (const serverType: TServerType): IAurelius; 
begin 
    case serverType of 
    stLocal: result:=TAureliusLocal.Create(path); 
    stFireDac: result:=TAureliusFireDac.Create(....); 
    end; 
end; 

...你只是这样称呼它:

var 
    currentDatabase: IAurelius; 
begin 
    currentDatabase:=createAureliusDatabase(stLocal,'c:\....'); 
end; 

处理创建数据库的更好方法是使用重载函数wi不同的参数或匿名方法来避免案例结束分支。

相关问题