-1

Das Ignorieren der Tatsache zu strukturieren, dass dies die Aurelius Framework verwendet, ist diese Frage mehr darüber, wie ich brauche den Code neu zwicken die allgemeine Konstruktor Injektion Arbeit für beide Arten zu machen:
< string>
und
< TCustomConnection>
auch die Tatsache ignorieren, dass die untergeordneten Objekte in derselben Einheit sind, würde ich sie im allgemeinen in ihrem eigenen stellen, aber das macht es nur einfacher in Frage zu stellen.Was ist der richtige Weg ist, diese generische Objekterstellung

Ich versuche mit dem Factory-Methode-Muster zu bestimmen, welche Art von Verbindung es zur Laufzeit abhängig von dem Objekt, das ich instanziieren sollte. Momentan wird der Typ der Verbindung festgeschrieben, die auf dem Create erwartet wird.

In dem Beispiel möchte ich einen TModelDatabaseLink übergeben, möchte aber zur Laufzeit entscheiden, um welche Art von Datenbankverbindung es sich handelt oder ob die Datenbankverbindung aus einer Datei stammt. Ja, ich weiß, dass ich FFilename auskommentieren könnte und einfach die Dateinamenversion behalten würde, aber ich bin immer daran interessiert, ein bisschen mehr zu lernen.

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. 

Eine andere Sache Ich mag würde, wenn möglich, tun, ist zwei Kreationen zu ändern:

LAdapter := TSQLiteNativeConnectionAdapter.Create(LFilename) 

LAdapter := TFireDacConnectionAdapter.Create(FDatabaseLink.FConnection as TFDConnection, FDatabaseLink.OwnedComponent) 

eine abstrakte „GetAdapterClass“ Typ-Funktion in der übergeordneten TModelDatabaseConnection zu verwenden und erklären, nur die Klasse Adapter in dem Kind zu tun, so etwas wie:

LAdapter := GetAdapterClass.Create... 

ein Beispiel einer Adapters Erklärung

TFireDacConnectionAdapter = class(TDriverConnectionAdapter<TFDConnection>, IDBConnection) 
+0

Könnte es sein, dass Sie mit den Spring.Persistence-Adaptern arbeiten? Weil mir dieser Code sehr bekannt vorkommt. Wenn ja, schauen Sie in Spring.Persistence.Core.ConnectionFactory.pas, wie verschiedene Ctor-Parameter für die angepasste Verbindung injiziert werden. –

+0

Hey Stefan. Dies sind eigentlich diejenigen aus dem TMS Aurelius-Framework, um ehrlich zu sein.Ich werde mir aber auch die Spring-Unit ansehen, da ich sie auch auf meinem PC habe, um zu sehen, ob sie mir weitere Hinweise gibt. – mikelittlewood

+0

Hallo Stefan. In Spring.Persistence.Adapters.SQLite geben Sie an, dass Sie eine TSQLiteDatabase und nicht nur einen Dateinamen übergeben müssen. Der einzige, den ich im Spring-Code finden kann, ist der unter .. \ Marshmallow \ External \ SQLite3. Ist das ein "offizieller" Frühling? – mikelittlewood

Antwort

0

Ich habe das schon einmal gemacht, als ich eine abstrakte Ebene geschrieben habe, falls ich Aurelius in meinen Anwendungen ersetzen muss. Ich denke, der beste Weg, um mit dem, was Sie tun möchten, zu tun, ist die Verwendung von Schnittstellen.

Ich kopiere hier einige Teile meines Codes mit Anpassungen:

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; 

ich den Code für alle getXXX Funktionen hier überspringen werde.

Die Konstrukteure sind diese:

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; 

Nun, wenn Sie eine Datenbank Aurelius Sie folgende Funktionen verwenden erstellen möchten:

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

... und Sie es einfach wie folgt aufrufen:

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

Eine bessere Möglichkeit, mit der Erstellung der Datenbank umzugehen, ist die Verwendung überladener Funktionen wi th verschiedene Parameter oder anonyme Methoden, um den Fall-Ende-Zweig zu vermeiden.

Verwandte Themen