-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不同的參數或匿名方法來避免案例結束分支。

相關問題