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)
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. –
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
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