Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Tutorials und Kurse (https://www.delphipraxis.net/36-tutorials-und-kurse/)
-   -   [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank (https://www.delphipraxis.net/193418-%5Btutorial%5D-laden-speichern-von-objekten-einer-normalisierten-datenbank.html)

haentschman 27. Jul 2017 13:58

[Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo...:P

Das ist mein erstes Tutorial. Bitte seid gnädig... Es soll als Anregung dienen wie man auch ohne datensensitive Controls auskommt. :thumb:

Ich möchte Euch zeigen, wie man programmintern mit Objekten arbeitet und diese Objekte in einer normalisierten Datenbank speichert. Im Prinzip ist es
ein Mini-ORM ohne externes Framework. Der Kreativität sind keine Grenzen gesetzt.
Ich habe versucht das einfach zu halten. Mancher Code könnte mit unterschiedlichen Methoden realisiert werden. (JOIN statt separater procedure) Welche Variante
man nimmt, ist jedem selbst überlassen.

Hinweise:

* Weil die Units zu lang sind... siehe Projekt.
* Weil nicht alle das compilieren können ist die EXE zum Ausprobieren dabei... siehe Projekt
* Die Zwischenvariablen (wie var Customer: TCustomer; in Main) sind nicht immer notwendig aber es macht es für den Anfang imho übersichtlicher.

Anhänge:
* Projekt mit Datenbank ausführbar.
* kompletter Quelltext D10.1

Voraussetzungen:
Delphi XE und höher wegen Generics im Beispiel

Aufbau 3 Schicht Anwendung:
(Unit: FormMain) -> (Unit: Logic) -> (Unit: Database) -> (Database: z.B.Firebird)
<- (Event) <- (Event)

Database (beliebiebiges DBMS)
Code:
CREATE TABLE T_CUSTOMER (
    ID               INTEGER NOT NULL,
    F_NAME           VARCHAR(50),
    F_FIRST_NAME     VARCHAR(50),
    F_ADDRESS_ID     INTEGER
);


CREATE TABLE T_ADDRESS (
    ID                INTEGER NOT NULL,
    F_POSTCODE        VARCHAR(30),
    F_TOWN            VARCHAR(50),
    F_STREET          VARCHAR(50),
    F_HOUSE_NUMBER    VARCHAR(10)
);
Unit: Database
In dieser Unit ist die Schnittstelle zur Datenbank definiert. In diesem Falle als Interface. Die Logik kennt nur das Interface welches in der Logik instanziert wird. (siehe Unit: Logik)
Die Querys werden nicht mehr auf die Form "geklatscht" und dort die SQL eingetragen. Das Interface kennt alleinig die SQL Statements.
Das macht es einfacher mehrere Datenbanken anzubinden. Für jede Datenbank gibt es dann ein eigenes Interface wegen der Unterschiede der möglichen Datenbanken.
Als Datenbankkomponenten kommen hier die UniDAC mit der Schnittstelle zu Firebird zum Einsatz. Andere Komponenten sind natürlich auch möglich.
Diese eine Unit kennt allein die Datenbank. Die Kommunikation mit der Logik, welche die Unit nicht kennt, kann sowohl über Events oder als Rückgabe der Funktion
aus der Logik erfolgen.

Interface:
Delphi-Quellcode:
unit Database.Interfaces;

interface

uses
  Logic.DataClasses,
  Database.Events;

type
  IDatabaseCommon = interface(IInterface) // ggf. in seperate Unit bei mehreren DBMS
  ['{E41ADEE8-56F9-4223-8238-61B6C033DFF1}']
    function GetAfterConnect: TOnAfterConnectEvent;
    procedure SetAfterConnect(const Value: TOnAfterConnectEvent);
    function GetDatabaseError: TOnDatabaseErrorEvent;
    procedure SetDatabaseError(const Value: TOnDatabaseErrorEvent);
    function GetAfterDisconnect: TOnAfterDisconnectEvent;
    procedure SetAfterDisconnect(const Value: TOnAfterDisconnectEvent);

    property OnAfterConnect: TOnAfterConnectEvent read GetAfterConnect write SetAfterConnect;
    property OnAfterDisconnect: TOnAfterDisconnectEvent read GetAfterDisconnect write SetAfterDisconnect;
    property OnDatabaseError: TOnDatabaseErrorEvent read GetDatabaseError write SetDatabaseError;

    function Connect: Boolean;
    procedure Disconnect;
    procedure StartTransaction;
    procedure Commit;
    procedure Rollback;

    function GetSQLByName(SQLName: string): string; // ggf. bei Laden des SQL Statements aus Ressource
  end;

  IDatabase = interface(IDatabaseCommon)
    ['{C1BC6FE3-9586-4D92-8221-A3DD030E80B5}']
    // Entweder overload oder als einzelne Prozeduren, der Creativität sind keine Grenzen gesetzt.
    procedure FillList(List: TCustomerList); overload;

    function Save(Customer: TCustomer): Integer; overload;
    function Save(Address: TAddress): Integer; overload;

    procedure Get(Customer: TCustomer; ID: Integer); overload;
    procedure Get(Address: TAddress; ID: Integer); overload; // kann auch separat genutzt werden...oder auch nicht
  end;


implementation

end.
Database gekürzt:
Delphi-Quellcode:
unit Database.Firebird;

interface

uses
  System.Classes, System.SysUtils, System.Variants, System.Generics.Collections, System.Generics.Defaults, System.DateUtils,
  Uni, DBAccess, InterBaseUniProvider,
  Database.Interfaces, Database.Events,
  Logic.DataClasses;

type
  TDatabaseFirebird = class(TInterfacedObject, IDatabase)
  strict private
    // Properties Connection
    FConnection: TUniConnection;
    FOnAfterConnect: TOnAfterConnectEvent;
    FOnAfterDisconnect: TOnAfterDisconnectEvent;
    FOnDatabaseError: TOnDatabaseErrorEvent;
    // Getter / Setter
    function GetAfterConnect: TOnAfterConnectEvent;
    procedure SetAfterConnect(const Value: TOnAfterConnectEvent);
    function GetDatabaseError: TOnDatabaseErrorEvent;
    procedure SetDatabaseError(const Value: TOnDatabaseErrorEvent);
    function GetAfterDisconnect: TOnAfterDisconnectEvent;
    procedure SetAfterDisconnect(const Value: TOnAfterDisconnectEvent);
    // Eventhandler
    procedure DoAfterConnect(Sender: TObject);
    procedure DoAfterDisconnect(Sender: TObject);
    procedure DoError(Sender: TObject; E: EDAError; var Fail: Boolean);
    // Funktionen
    function CreateQuery: TUniQuery;
  public
    constructor Create;
    destructor Destroy; override;
    // Events
    property OnAfterConnect: TOnAfterConnectEvent read GetAfterConnect write SetAfterConnect;
    property OnAfterDisconnect: TOnAfterDisconnectEvent read GetAfterDisconnect write SetAfterDisconnect;
    property OnDatabaseError: TOnDatabaseErrorEvent read GetDatabaseError write SetDatabaseError;
    // Funktionen aus Interface
    function Connect: Boolean;
    procedure Disconnect;
    procedure StartTransaction;
    procedure Commit;
    procedure Rollback;

    function GetSQLByName(SQLName: string): string; // ggf. bei Laden des SQL Statements aus Ressource

    procedure FillList(List: TCustomerList); overload;

    function Save(Customer: TCustomer): Integer; overload;
    function Save(Address: TAddress): Integer; overload;

    procedure Get(Customer: TCustomer; ID: Integer); overload;
    procedure Get(Address: TAddress; ID: Integer); overload; // kann auch separat genutzt werden...oder auch nicht
  end;
 
...
Unit: Logic
In dieser Unit ist die Logik definiert. Die Logik nimmt die Befehle der Form entgegen und führt diese aus. Desweiteren hällt die Logik die Daten der Anwendung. In diesem
Falle die CustomerList. Die Kommunikation mit der Form, welche die Unit nicht kennt, kann sowohl über Events oder als Rückgabe der Function aus der Logik erfolgen.

Klassendefinition gekürzt:
Delphi-Quellcode:
unit Logic.DataClasses;

interface

uses
  System.Generics.Collections, System.Generics.Defaults;

type
  TDataState = (ddsNormal, ddsNew, ddsModified, ddsDeleted);

  TBaseClass = class
  strict protected
    FID: Integer;
    FState: TDataState; // jedes Objekt kennt seinen Status
  public
    property ID: Integer read FID write FID;
    property State: TDataState read FState write FState;
  end;

  TAddress = class(TBaseClass)
  strict private
    FTown: string;
    FStreet: string;
    FPostCode: string;
    FHouseNumber: string;
  public
    constructor Create;
    destructor Destroy; override;
    property PostCode: string read FPostCode write FPostCode;
    property Town: string read FTown write FTown;
    property Street: string read FStreet write FStreet;
    property HouseNumber: string read FHouseNumber write FHouseNumber;
  end;

  TCustomer = class(TBaseClass)
  strict private
    FName: string;
    FAddress: TAddress;
    FFirstName: string;
  public
    constructor Create;
    destructor Destroy; override;
    property Name: string read FName write FName;
    property FirstName: string read FFirstName write FFirstName;
    property Address: TAddress read FAddress write FAddress;
  end;

  TCustomerList = TObjectList<TCustomer>;
...
Logic gekürzt:
Delphi-Quellcode:
unit Logic.Base;

interface

uses
  Database.Interfaces, Database.Firebird, Database.Events,
  Logic.DataClasses;

type
  TOnFillCustomerListEvent = procedure(Sender: TObject; List: TCustomerList) of object;
  TOnGetCustomerEvent = procedure(Sender: TObject; Customer: TCustomer) of object;
  TOnDataChangedEvent = procedure(Sender: TObject; State: Boolean) of object;

  TLogic = class
  strict private
    FDatabase: IDatabase;
    FCustomerList: TCustomerList;

    FOnConnectDatabase: TOnAfterConnectEvent;
    FOnDisconnectDatabase: TOnAfterDisconnectEvent;
    FOnDatabaseError: TOnDatabaseErrorEvent;
    FOnFillCustomerList: TOnFillCustomerListEvent;
    FOnGetCustomer: TOnGetCustomerEvent;

    procedure DoOnDatabaseError(Sender: TObject; ErrorNumber: Integer; ErrorMessage: string);
    procedure DoOnAfterConnect(Sender: TObject);
    procedure DoOnAfterDisconnect(Sender: TObject);
  private
    FDataChanged: Boolean;
    FOnDataChanged: TOnDataChangedEvent;
    procedure SetDataChanged(const Value: Boolean);
  public
    constructor Create;
    destructor Destroy; override;

    property OnConnectDatabase: TOnAfterConnectEvent read FOnConnectDatabase write FOnConnectDatabase;
    property OnDisconnectDatabase: TOnAfterDisconnectEvent read FOnDisconnectDatabase write FOnDisconnectDatabase;
    property OnDatabaseError: TOnDatabaseErrorEvent read FOnDatabaseError write FOnDatabaseError;
    property OnFillCustomerList: TOnFillCustomerListEvent read FOnFillCustomerList write FOnFillCustomerList;
    property OnGetCustomer: TOnGetCustomerEvent read FOnGetCustomer write FOnGetCustomer;
    property OnDataChanged: TOnDataChangedEvent read FOnDataChanged write FOnDataChanged;

    property DataChanged: Boolean read FDataChanged write SetDataChanged;

    property CustomerList: TCustomerList read FCustomerList;

    procedure GetCustomerList;
    procedure GetCustomer(ID: Integer);
    procedure SaveCustomer(Customer: TCustomer);
    procedure RefreshCustomerList;
  end;
...
Unit: FormMain gekürzt
In dieser Unit ist die Form mit den Controls definiert. Die Form gibt der Logic Befehle was sie an Informationen haben möchte. Über Events werden die Information aus der Logik
zurückgeliefert und verarbeitet.
Delphi-Quellcode:
unit FormMain;

interface

uses
  Winapi.Windows, Winapi.Messages,
  System.SysUtils, System.Variants, System.Actions, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.ActnList, Vcl.ComCtrls,
  ImageList.Small,
  Logic.Base, Logic.DataClasses;

const
  conTextGroupboxNormal = 'Details (Normal)';
  conTextGroupboxEdit = 'Details (Editmodus)';

type
  TfoMain = class(TForm)
    pnlTop: TPanel;
    pnlContent: TPanel;
    lvCustomers: TListView;
    btnNew: TButton;
    btnCopy: TButton;
    btnDelete: TButton;
    grpDetails: TGroupBox;
    btnSave: TButton;
    edtName: TEdit;
    lblName: TLabel;
    edtFirstName: TEdit;
    lblFirstName: TLabel;
    edtPostCode: TEdit;
    lblPostCode: TLabel;
    edtTown: TEdit;
    lblTown: TLabel;
    edtStreet: TEdit;
    lblStreet: TLabel;
    edtHouseNumber: TEdit;
    lblHouseNumber: TLabel;
    actlstMain: TActionList;
    actNew: TAction;
    btnInfo: TButton;
    actCopy: TAction;
    actDelete: TAction;
    actInfo: TAction;
    actSave: TAction;
    actCancel: TAction;
    btnCancel: TButton;
    btnMessage: TButton;
    actMessage: TAction;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure actNewExecute(Sender: TObject);
    procedure actCopyExecute(Sender: TObject);
    procedure actDeleteExecute(Sender: TObject);
    procedure actInfoExecute(Sender: TObject);
    procedure actSaveExecute(Sender: TObject);
    procedure actCancelExecute(Sender: TObject);
    procedure lvCustomersChange(Sender: TObject; Item: TListItem; Change: TItemChange);
    procedure actMessageExecute(Sender: TObject);
  private
    FLogic: TLogic;
    procedure DoFillCustomerList(Sender: TObject; List: TCustomerList);
    procedure DoGetCustomer(Sender: TObject; Customer: TCustomer);
    procedure DoDataChanged(Sender: TObject; State: Boolean);

    procedure ShowCustomerList(List: TCustomerList);
    procedure ShowCustomer(Customer: TCustomer);
    procedure SetCustomerToEdit(Active: Boolean);
    procedure SetButtons(Active: Boolean);
  public

  end;

var
  foMain: TfoMain;
...

Prinzip des Datenholens:

Delphi-Quellcode:
procedure TDatabaseFirebird.Get(Customer: TCustomer; ID: Integer); // nur einen Customer holen
var
  Qry: TUniQuery;
begin
  Qry := CreateQuery; // Query incl. der Connection erzeugen
  try
    // SQL wie gehabt
    Qry.SQL.Text := 'SELECT * FROM T_CUSTOMER WHERE ID = :ID';
//  Alternativ über Ressource: Qry.SQL.Text := GetSQLByName('xxx'); // SQL Name ergänzen
    Qry.ParamByName('ID').AsInteger := ID;
    Qry.Open;
   
    // das Objekt füllen
    Customer.ID := Qry.FieldByName('ID').AsInteger;
    Customer.Name := Qry.FieldByName('F_NAME').AsString;
    Customer.FirstName := Qry.FieldByName('F_FIRST_NAME').AsString;
    // Alternative für GET wäre ein JOIN im Statement und die Adresse hier zusammenbauen.
    // Der Vorteil der Trennung: Man kann auch die Adresse seperat lesen. Wie man es braucht... :-)
    Get(Customer.Address, Qry.FieldByName('F_ADDRESS_ID').AsInteger);
    Customer.State := ddsNormal; // Wichtig: Status setzen
  finally
    Qry.Free;
  end;
end;

...

procedure TDatabaseFirebird.FillList(List: TCustomerList); // komplette Liste füllen
var
  Qry: TUniQuery;
  Customer: TCustomer;
begin
  List.Clear;
  Qry := CreateQuery; // Query incl. der Connection erzeugen
  try
    Qry.SQL.Text := 'SELECT * FROM T_CUSTOMER';
//  Alternativ über Ressource: Qry.SQL.Text := GetSQLByName('xxx'); // SQL Name ergänzen
    Qry.Open;
    while not Qry.Eof do
    begin
      Customer := TCustomer.Create; // Objekt erzeuggen
      Get(Customer, Qry.FieldByName('ID').AsInteger); // Objekt füllen
      List.Add(Customer); // Objekt in Liste legen
      Qry.Next;
    end;
  finally
    Qry.Free;
  end;
end;
Prinzip der Speicherung
Delphi-Quellcode:
function TDatabaseFirebird.Save(Customer: TCustomer): Integer; // Speichern
var
  Qry: TUniQuery;
begin
  Result := -1;
  Qry := CreateQuery;
  try
    StartTransaction;
    try
      case Customer.State of // entsprechend dem Status des Objektes
        ddsNew: // insert
          begin
            Customer.Address.ID := Save(Customer.Address); // Rückgabe der ID als Erstes wegen ID
            Qry.SQL.Text := 'INSERT INTO T_CUSTOMER (F_NAME, F_FIRST_NAME, F_ADDRESS_ID) VALUES (:NAM, :FIN, :ADD) returning ID';
            //  Alternativ über Ressource: Qry.SQL.Text := GetSQLByName('xxx'); // SQL Name ergänzen
            // das Objekt dem SQL übergeben
            Qry.ParamByName('NAM').AsString := Customer.Name;
            Qry.ParamByName('FIN').AsString := Customer.FirstName;
            Qry.ParamByName('ADD').AsInteger := Customer.Address.ID;
            Qry.ExecSQL;
            Customer.ID := Qry.ParamByName('RET_ID').AsInteger;

            Customer.State := ddsNormal;
            Result := Customer.ID;
          end;
        ddsModified: // update
          begin
            Qry.SQL.Text := 'UPDATE T_CUSTOMER SET F_NAME = :NAM, F_FIRST_NAME = :FIN, F_ADDRESS_ID = :ADD WHERE ID = :ID';
            //  Alternativ über Ressource: Qry.SQL.Text := GetSQLByName('xxx'); // SQL Name ergänzen
            // das Objekt dem SQL übergeben
            Qry.ParamByName('ID').AsInteger := Customer.ID;
            Qry.ParamByName('NAM').AsString := Customer.Name;
            Qry.ParamByName('FIN').AsString := Customer.FirstName;
            Qry.ParamByName('ADD').AsInteger := Customer.Address.ID;
            Qry.ExecSQL;

            Save(Customer.Address);

            Customer.State := ddsNormal;
            Customer.Address.State := ddsNormal;
            Result := Customer.ID;
          end;
        ddsDeleted: // deleted
          begin
            Qry.SQL.Text := 'DELETE FROM T_CUSTOMER WHERE ID = :ID';
            //  Alternativ über Ressource: Qry.SQL.Text := GetSQLByName('xxx'); // SQL Name ergänzen
            Qry.ParamByName('ID').AsInteger := Customer.ID;
            Qry.ExecSQL;

            Customer.Address.State := ddsDeleted;
            Save(Customer.Address);

            Result := Customer.ID;
          end;
      end;

      Commit;
    except
      Rollback;
    end;
  finally
    Qry.Free;
  end;
end;
Prinzip der Datenanzeige
Delphi-Quellcode:
procedure TfoMain.DoFillCustomerList(Sender: TObject; List: TCustomerList); // Event nach dem Datenholen
begin
  ShowCustomerList(List);
  SetCustomerToEdit(False);
end;

...

procedure TfoMain.ShowCustomerList(List: TCustomerList);
var
  Item: TListItem;
  Customer: TCustomer;
begin
  lvCustomers.Items.Clear;
  for Customer in List do
  begin
    Item:= lvCustomers.Items.Add;
    Item.Data:= Customer; // Das Objekt (Pointer) hängt an dem Eintrag
    Item.SubItems.Add(Customer.Name);
    Item.SubItems.Add(Customer.FirstName);
    Item.SubItems.Add(Customer.Address.Town);
    Item.ImageIndex:= dmSmall.GetIconIndexDataState(Customer.State);
  end;
  lvCustomers.Items.Item[0].Selected := True; // ersten Eintrag markieren...oder so
end;
Erweiterungen:
Nach Bedarf können u.a. Funktionen hinzugefügt oder mit einander kombiniert werden. (DRY)

Vorteile:
* Keine datensensitiven Controls. Das bedeutet Unabhängigkeit von der Optik der DB sensitiven Controls.
* Eine Property des Objektes kann z.B. in einem TEdit einem TMemo oder mit einem TRotMitGelbenPunktenControl dargestellt werden.
* Alle SQL Statements auf einem Fleck. Das erleichtert das Suchen nach einem Statement. Die SQL sind nicht mehr auf den gesamten QT verteilt.
* Die Umbauten bei Datenbankwechsel beziehen sich nur auf das Interface.
* Durch die Objekte kann man sich die Informationen beliebig zustammenstellen. Auch wenn sie auch verschieden Tabelle stammen.
* Speichern mit einem Einzeiler
Delphi-Quellcode:
FDatabase.Save(Customer);
...
* Objekte sind besser debugbar.
* Objekte können wiederum Listen mit Objekten enthalten.
* Objekte sind mit einem Rutsch, über das Database Interface, speicherbar.

Bei diesem Tutorial geht es ums Prinzip bei der Arbeit mit Objekten ohne die üblichen Verdächtigen der großen Frameworks für Datenbanken. Meistens lohnt der Aufwand nicht
ein großes Framework zu installieren. Auch der Einarbeitungsaufwand bei diesen ist nicht ohne... Manchmal ist weniger mehr. 8-)


Diskussion eröffnet.

PS: Alle Fehler sind urheberrechtlich geschützt weil Unikate. :zwinker:

Rollo62 27. Jul 2017 14:35

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Wieso nur gnädig, ich bin doch immer froh wenn sich einer die Zeit nimmt etwas genauer zu erklären :-D

Ich frage mich bei dem ganzen ORM nur immer ob es der richtige Weg ist.
Datenbanken wurde noch gemacht um 1 bis 1Mio. Datensätze zu verwalten.
ORM mit Listen im Speicher (OK, ich lass man das intelligente Speicherverwalten weg),
das läuft doch bei 1 Mio. Datensätze in eine Krise.

Dann die Anbindung der Daten an die Controls.
Im Prinzip bin ich ja voll dafür, also heist die Richtung LiveBinding,
nur leider funktioniert das nur rudimentär.
Welches Konzept hast du denn dafür, etwas Eigenes drüberstülpen ?

Rollo

Jumpy 27. Jul 2017 14:42

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Zitat:

Zitat von Rollo62 (Beitrag 1377621)
Ich frage mich bei dem ganzen ORM nur immer ob es der richtige Weg ist.
Datenbanken wurde noch gemacht um 1 bis 1Mio. Datensätze zu verwalten.
ORM mit Listen im Speicher (OK, ich lass man das intelligente Speicherverwalten weg),
das läuft doch bei 1 Mio. Datensätze in eine Krise.

Ob du nun die 1 Mio. Datensätze in Listen mit Objekten oder aber in einem Dataset hast, wenn du dir 1 Mio. Datensätze von der DB holst, hast du die halt im Speicher. Aufpassen was du dir an Datensätzen holst must du immer selber, egal ob mit oder ohne ORM.

haentschman 27. Jul 2017 15:06

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Hallöle...:P
Zitat:

Ich frage mich bei dem ganzen ORM nur immer ob es der richtige Weg ist.
...für mich gibt es keinen Anderen. 8-) Ich bin durch die Einschränkungen der datensensitiven Controls, der Datasets, und vor Allem dem Durcheinander mit den Querys auf den Forms dazu gekommen. Im früherem Leben habe ich auch die Queries auf der Form mit DB Controls gehabt. :oops: Mit steigenden Anforderungen war das mir einfach zu unübersichtlich. Deshalb habe ich nach einer anderen Möglichkeit gesucht und gefunden...:thumb:
Zitat:

ORM mit Listen im Speicher (OK, ich lass man das intelligente Speicherverwalten weg), das läuft doch bei 1 Mio. Datensätze in eine Krise.
...wie schon Jumpy sagte:
Zitat:

Ob du nun die 1 Mio. Datensätze in Listen mit Objekten oder aber in einem Dataset hast, wenn du dir 1 Mio. Datensätze von der DB holst, hast du die halt im Speicher. Aufpassen was du dir an Datensätzen holst must du immer selber, egal ob mit oder ohne ORM.
...du mußt selbst entscheiden welche Datensätze zu holst. :wink: Der Rest liegt im Datengrab...

Zitat:

Dann die Anbindung der Daten an die Controls.
...wo ist das Problem? Manches muß man auch manuell machen. Dafür heißt es auch programmieren... 8-)
Zitat:

Im Prinzip bin ich ja voll dafür, also heist die Richtung LiveBinding, nur leider funktioniert das nur rudimentär.
Livebindings habe ich probiert. Overhead war mir deutlich zu groß. Dann lieber klassisch. http://www.delphipraxis.net/190711-l...ceadapter.html
Zitat:

Welches Konzept hast du denn dafür, etwas Eigenes drüberstülpen ?
...weniger Probleme. :stupid:

Rollo62 27. Jul 2017 16:21

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Ich binn dann wohl immer noch im Irrglauben das die Datasets nicht Alle Daten im Speicher halten, sondern nur intelligent per Chinks sich die passenden Häppchen holen.

Das hängt sicher vom Query ab, ein FDMemTable oder ClientDataSet hat Alles im Speicher,
aber was ist mit TFDQuery, oder ähnlichen Konstrukten ?

Die sollen das doch genau das Daten- und MemoryManagement vor mir Kapseln.

ORM ist gut und richtig, das sehe ich auch so.
Aber warum eigentlich nicht direkt von TDataset auf die Controls binden ?
Warum unbedings Objekte dazwischenbauen ?
(Ok, ich verstehe das man in den Objekten tolle Logik reinbauen kann, aber sollte man das wirklich dort machen) ?

Mit einer Wrapperklasse sollte das doch "einfach" möglichs ein.
TDbGrid macht das doch im Prinzip auch so, nur der der Wrapper im DBGrid selber ist, sozusagen.

LiveBinding per Code macht das im Prinzip so, mit FillExpressions z.B. für ListView,
und da glaube ich eben auch das dies der richtige Weg ist, das per RTTI zu entkoppeln.

So in dieser Richtung, am liebsten per Code:
Delphi-Quellcode:
   FDb.Bind(Query1, ListView, 'Name', 'Text')
      .Bind(Query1, ListView, 'Descr', 'Detail')
      .Bind(Query1, ListView, 'ImgId', 'ImageIndex')
      .Bind(Query1, Grid1,   '*')
      .Bind(Query1, Edit1,   'Name', 'Text', dbBidirectional)
      ...
      ;

Rollo

Uwe Raabe 27. Jul 2017 16:29

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Zitat:

Zitat von Rollo62 (Beitrag 1377639)
Ich binn dann wohl immer noch im Irrglauben das die Datasets nicht Alle Daten im Speicher halten, sondern nur intelligent per Chinks sich die passenden Häppchen holen.

Das hängt sicher vom Query ab, ein FDMemTable oder ClientDataSet hat Alles im Speicher,
aber was ist mit TFDQuery, oder ähnlichen Konstrukten ?

TFDQuery holt sich zwar die Daten häppchenweise, behält diese aber im Speicher - außer, es ist Unidirectional aktiv, dann werden die bereits besuchten Datensätze wieder aus dem Speicher geworfen.

Bezüglich ORM und DataSet/DBControls: Bei TMS Aurelius gibt es extra ein
Delphi-Quellcode:
TAureliusDataset
um die beiden Welten wieder zu vereinen.

haentschman 27. Jul 2017 17:09

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Zitat:

Aber warum eigentlich nicht direkt von TDataset auf die Controls binden ?
1. u.a. Faulheit. Ich habe die Faxen von ständig Query.FieldByName('FBlubb').AsInteger voll. :stupid:
2. Weil ich die Daten im DataSet nicht strukturieren kann. Ähnlich einer Ordnerstruktur. :thumb:
Zitat:

Warum unbedings Objekte dazwischenbauen ?
1. Im Quelltext steht kein einziger Feldname. :thumb:
2. Die Datenbank oder die Datenquelle ist komplett getrennt. :thumb: Die Daten können über das Interface aus Oma´s Küchenschrank kommen. Der Küchenschrank kennt kein DataSet sondern XML... :stupid:
3. Das macht das Wechseln zwischen den Datenbanken / Quellen einfacher. Getrennte Statements je Interface für die verschieden DBMS.
4. Am Breakpoint kann man sich das komplette Objekt mit seinen Daten ansehen. :thumb:

:warn: eine Bitte:
Zitat:

Bei TMS Aurelius gibt es
...das wir in diesem Tutorial nur über dieses Beispiel ORM diskutieren. Danke. :wink:

Rollo62 27. Jul 2017 18:15

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Wenn ich das richtig sehe hast du keine Interaktion drin, die Controls werden gefüllt.
Der Spass fängt aber dann an wenn du ein Grid oder Listview scrollen und editieren möchtest,
wenn Master-Detail sich synchronisieren müssen, korrekt die Daten in die DB zurückschreiben, etc..
Das müsste ja meiner Meinung nach auch gekapselt werden, das will man nicht immer wieder neu schreiben müssen.
Ich sehe das so das es eine Art "Bindings" in irgendeiner Form geben müsste, zum einen für die Daten (so wie du es hast z.B.), zum anderen eben diese Events (abhängig vom jeweiligen Control
und "Style" der Bedienung).

Wie würdest du denn so etwas bei deinem Vorschlag lösen ?

Rollo

Fritzew 27. Jul 2017 18:29

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Danke für das Tutorial.
Da es nicht nur ORM sondern auch Interfaces behandelt, oder besser gesagt auch zeigt wie die Benutzung aussehen kann, finde ich es wirklich gut.
Klar gibt es da viele verschiedene Ansätze, aber um aufzuzeigen wie man etwas auch anders machen kann finde ich es toll.
Was mit immer wieder auffällt in unserer "Delphi" Welt, ist das neue Ansätze es hier wirklich schwer haben.

p80286 27. Jul 2017 19:08

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Erst einmal vielen Dank!

Für den Datenbank-Teil hätte ich noch die eine oder andere Idee, aber das wären nur Detailänderungen, die mir pers. besser in den Kram passen würden. Den Interface-Teil habe ich zwar verstanden, glaube ich, aber der Vorteil erschließt sich mir nicht so recht. Mit einem TDataModule kommt man (ich) genauso weit, einziges Problem(?) für jede DB brauch ich ein eigenes Modul aber ein
Delphi-Quellcode:
MyDM.GetPersonList(pl:tPersonlist)
sollte immer die (formal) gleiche Liste liefern.

Gruß
K-H

haentschman 28. Jul 2017 06:10

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Liste der Anhänge anzeigen (Anzahl: 2)
Moin...:P
Zitat:

Danke für das Tutorial.
Zitat:

Erst einmal vielen Dank!
...Dankeschön. :P

Zitat:

Der Spass fängt aber dann an wenn du ein Grid oder Listview scrollen und editieren möchtest,
Zitat:

Wie würdest du denn so etwas bei deinem Vorschlag lösen ?
Persönlich habe ich mich entschieden, daß niemals in der Listview editiert wird. Das hatte den Grund, daß mehr Informationen zu editieren waren als Spalten optisch zur Verfügung standen. Zum Editieren blende ich einfach eine modale Form über die Listview ein. Ich nenne sie InlineEditor. (siehe Bild 1) Damit kann ich beliebige Informationen editieren und die Controls im InlineEditor selbst, auch wegen der Optik, festlegen. Dem InlineEditor wird das Objekt, welches am Listvieweintrag hängt, übergeben...usw. (siehe Bild 2) Am Objekt kann man sehen, daß das mit dem Dataset nicht übersichtlich möglich ist. Das Objekt würde eigentlich aus mindestens 3 Datasets bestehen. 8-)
Zitat:

Das müsste ja meiner Meinung nach auch gekapselt werden, das will man nicht immer wieder neu schreiben müssen.
Der Kreativität sind keine Grenzen gesetzt. :thumb: In meinen Produktivprojekten ist einiges als gemeinsamer Code ausgelagert um nicht alles neu schreiben zu müssen. Beispiel. Der InlineEditor. Den leite ich von der Basis, mit aller Logik für die Anzeige etc., ab.
...aber das würde zu weit führen und hat nichts mit dem Thema zu tun. :wink:
Zitat:

aber das wären nur Detailänderungen, die mir pers. besser in den Kram passen würden.
Der Kreativität sind keine Grenzen gesetzt. :thumb: Du kannst das Prinzip für deine Bedürfnisse anpassen.
Zitat:

sollte immer die (formal) gleiche Liste liefern.
...das ist korrekt.
Zitat:

Mit einem TDataModule kommt man (ich) genauso weit, einziges Problem(?) für jede DB brauch ich ein eigenes Modul
1. Wenn eh keine Querykomponenten auf dem DataModule liegen kannst du dir das auch sparen. :zwinker: Prinzipiell kommst du auch mit einem DataModule für eine Datenbank zurecht. Wenn du ein neues DBMS dazunimmst, kommst du um eine Abstraktion nicht herum.
Delphi-Quellcode:
// Klassendefinition oder so ähnlich
TDataBaseAbstract = class
public
  procedure Blubb; abstract;
end;
...
TDataBase1 = class(TDataBaseAbstract)
public
  procedure Blubb; override; // die spezielle Implementierung für Blubb
end;
...
TDataBase2 = class(TDataBaseAbstract)
public
  procedure Blubb; override; // die spezielle Implementierung für Blubb
end;

// Instanz
FDatabase: TDataBaseAbstract;
...
FDatabase := TDataBase2.Create; // oder so...
...die Vorteile von Interfaces wurde schon an anderer Stelle diskutiert. http://www.delphipraxis.net/192364-t...nterfaces.html

p80286 28. Jul 2017 12:06

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Zitat:

Zitat von haentschman (Beitrag 1377665)
Prinzipiell kommst du auch mit einem DataModule für eine Datenbank zurecht. Wenn du ein neues DBMS dazunimmst, kommst du um eine Abstraktion nicht herum.

Danke, das hätte man mir ja auch gleich so erklären können:oops:, die ODenke hab ich eben immer noch nicht ganz verinnerlicht.

Gruß
K-H

haentschman 28. Jul 2017 12:49

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Hallöle...:P
Zitat:

Danke, das hätte man mir ja auch gleich so erklären können
8-) Das wichtige ist nicht das Interface. Ein Datenmodul tut es auch. :P Sondern die Verlagerung aller SQL Statements in eine Unit ist Voraussetzung. :thumb: Dann kann man "schnell" wechseln...

KodeZwerg 23. Mai 2018 23:41

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Hallo, Vorweg: Das Tutorial ist gut gelungen auch wenn da mehr Code gezeigt wird als das Code erklärt wird.
Neugierig wie ich bin plus DB Neuling habe ich mir das Projekt geladen und beim Start der .exe erscheint das (gekürzt aufs wesentliche):
Zitat:

executable : Tutorial.exe
exec. date/time : 2017-07-27 14:01
version : 1.0.0.0
compiled with : Delphi 10.1 Berlin
madExcept version : 4.0.16
callstack crc : $0c5e2cf1, $23db6709, $23db6709
exception number : 1
exception class : EAccessViolation
exception message : Zugriffsverletzung bei Adresse 007FF967 in Modul 'Tutorial.exe'. Lesen von Adresse 00000008.

main thread ($11f8):
007ff967 +00b Tutorial.exe Logic.Base 143 +2 TLogic.GetCustomerList
00800a6e +026 Tutorial.exe FormMain 210 +2 TfoMain.FormShow
0065a34d +015 Tutorial.exe Vcl.Forms TCustomForm.DoShow
0065ebb9 +0a9 Tutorial.exe Vcl.Forms TCustomForm.CMShowingChanged
005a700e +2be Tutorial.exe Vcl.Controls TControl.WndProc
005abb59 +5e9 Tutorial.exe Vcl.Controls TWinControl.WndProc
0065ae0d +64d Tutorial.exe Vcl.Forms TCustomForm.WndProc
005a6c48 +024 Tutorial.exe Vcl.Controls TControl.Perform
005aaf21 +10d Tutorial.exe Vcl.Controls TWinControl.UpdateShowing
005ab030 +0bc Tutorial.exe Vcl.Controls TWinControl.UpdateControlState
005adc2a +026 Tutorial.exe Vcl.Controls TWinControl.CMVisibleChanged
005a700e +2be Tutorial.exe Vcl.Controls TControl.WndProc
005abb59 +5e9 Tutorial.exe Vcl.Controls TWinControl.WndProc
0065ae0d +64d Tutorial.exe Vcl.Forms TCustomForm.WndProc
005a6c48 +024 Tutorial.exe Vcl.Controls TControl.Perform
005a55fa +026 Tutorial.exe Vcl.Controls TControl.SetVisible
0065a629 +03d Tutorial.exe Vcl.Forms TCustomForm.SetVisible
00664897 +0b3 Tutorial.exe Vcl.Forms TApplication.Run
0080e9d9 +061 Tutorial.exe Tutorial 25 +5 initialization
77533675 +010 kernel32.dll BaseThreadInitThunk

thread $12f4:
77cd00f6 +0e ntdll.dll NtWaitForMultipleObjects
77533675 +10 kernel32.dll BaseThreadInitThunk

thread $1128:
77cd1edf +0b ntdll.dll NtWaitForWorkViaWorkerFactory
77533675 +10 kernel32.dll BaseThreadInitThunk

thread $104c:
77cd1edf +0b ntdll.dll NtWaitForWorkViaWorkerFactory
77533675 +10 kernel32.dll BaseThreadInitThunk

thread $afc:
77cd1edf +0b ntdll.dll NtWaitForWorkViaWorkerFactory
77533675 +10 kernel32.dll BaseThreadInitThunk

modules:
00400000 Tutorial.exe 1.0.0.0 \Win32
10000000 fbclient.dll 2.5.1.26351 \Win32
4a800000 icuuc30.dll 3.0.0.0 \Win32
4ad00000 icudt30.dll 3.0.0.0 \Win32

disassembling:
[...]
007ff95d mov ebp, esp
007ff95f push ecx
007ff960 push ebx
007ff961 mov [ebp-4], eax
007ff964 143 mov eax, [ebp-4]
007ff967 > mov edx, [eax+8]
007ff96a mov eax, [ebp-4]
007ff96d mov eax, [eax+4]
007ff970 mov ecx, [eax]
007ff972 call dword ptr [ecx+$3c]
007ff972
[...]
Müssen Voraussetzungen erfüllt werden um die .exe zu Starten?

haentschman 24. Mai 2018 05:46

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Moin...:P
Da ich auf der Arbeit kein UniDAC habe, kann ich es erst am Wochenende nachschauen. Aber normalerweise gibt es keine Voraussetzungen als die EXE im "out" Ordner zu starten. :gruebel:

Nachtrag:
Zitat:

da mehr Code gezeigt wird als das Code erklärt wird.
...mit Absicht. Nicht jede Zeile muß man erklären. Für tiefsinnige Fragen ist hier der Platz dafür. :zwinker:

mkinzler 24. Mai 2018 06:54

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Was steht den in der Zeile?

haentschman 24. Mai 2018 07:08

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Zitat:

007ff967 +00b Tutorial.exe Logic.Base 143 +2 TLogic.GetCustomerList
Delphi-Quellcode:
procedure TLogic.GetCustomerList;
begin
  // Daten holen und in die übergebene Liste ablegen
  FDatabase.FillList(FCustomerList); // <- 143 FCustomer List ist instanziert
  DataChanged := False; // Setter
  // Liste per Event übergeben
  if Assigned(FOnFillCustomerList) then
  begin
    FOnFillCustomerList(Self, FCustomerList);
  end;
end;
Delphi-Quellcode:
constructor TLogic.Create;
begin
  FDataChanged := False;
  // Customer Liste erstellen
  FCustomerList := TCustomerList.Create(True); // Instanz
  // Datenbank Interface
  FDatabase := TDatabaseFirebird.Create; // An diesem Punkt wird das Interface gewechselt auf ein anderes DBMS z.b. entsprechend der Einstellungen in der INI/XML usw.
  // Eventhandler einhängen
  FDatabase.OnAfterConnect := DoOnAfterConnect;
  FDatabase.OnAfterDisconnect := DoOnAfterDisconnect;
  FDatabase.OnDatabaseError := DoOnDatabaseError;

  FDatabase.Connect; // ggf. Prüfung auf Rückgabewert (Connected)
end;

destructor TLogic.Destroy;
begin
  FCustomerList.Free; // die enthaltenen Objekte werden automatisch weggeräumt.
  // Keine Freigabe des Interfaces nötig. :-)
  inherited;
end;

mkinzler 24. Mai 2018 07:15

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Liste der Anhänge anzeigen (Anzahl: 1)
Wenn man das Programm ausführt, kommt der Fehler bei mir auch. Selberkompiliert funktioniert es, nachdem ich die Datenbankverbindung auf embedded umgestellt habe.

Delphi-Quellcode:
FConnection.Server := ''; //'firma-server/3025'; // Embedded

haentschman 24. Mai 2018 07:29

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
:oops: Echt jetzt? Zu meiner Verteidigung...ich arbeite nie mit Embedded. :wink:
Zitat:

'firma-server/3025'; // Embedded
...das muß logischerweise raus! Ich hatte das noch "markiert" um es nicht zu vergessen. Getreu dem Motto: Wer nichts macht, macht nichts falsch...und wer nichts falsch macht, wird befördert.

@mkinzler: Danke.

KodeZwerg 24. Mai 2018 08:13

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Danke mkinzler, Deine .exe kann ich Starten!
Ich habe soeben Versucht das Projekt mit Tokyo zu öffnen = Package PngComponents fehlte mir, hab das von Uwe Raabe geladen und installiert also öffnen lässt es sich jetzt ohne Probleme.
Jetzt das nächste mir fehlende, Uni.pas. Ich vermute UniDAC ist damit gemeint und hier meine Frage:
Reicht da die Express oder muss ich die Pro Version nehmen? (ich = planlos da Neuling)

Vielen Dank für Hilfe!

Das MadExcept aus der .dpr habe ich auskommentiert, reicht das aus oder muss ich MadExcept dafür auch laden und installieren?

mkinzler 24. Mai 2018 08:24

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Nein. in der express fehlt der Treiber für Interbase/FireBird.
Man könnte aber auf Zeos, UIB o.ä umstellen.

haentschman 24. Mai 2018 08:28

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Zitat:

Das MadExcept aus der .dpr habe ich auskommentiert, reicht das aus oder muss ich MadExcept dafür auch laden und installieren?
...schlecht. :P Aber auch ohne den MadExcept geht das.
Zitat:

Reicht da die Express oder muss ich die Pro Version nehmen
Ich habe das Beispiel mit UniDAC entwickelt...Aber es geht auch jede andere Datenbankkomponente! Für den Anfang reichten die ZEOS. Einfach die UniQuery gegen die ZeosQuery tauschen ... fertsch. 8-)

so ungefähr:
Delphi-Quellcode:
function TDatabaseFirebird.CreateQuery: TZQuery;
begin
  Result := TZQuery.Create(nil);
  Result.Connection := FConnection;
end;
...logischerweise auch die Parameter der Connection anpassen. :wink:

KodeZwerg 24. Mai 2018 09:14

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Ich glaube das übersteigt gerade meine Grenzen, wenn ich "Uni, DBAccess, InterBaseUniProvider" weglasse ploppen da an sehr vielen Stellen fehlende Bezeichner auf wo ich bei meinem momentanen Wissensstand nicht wüßte wie ichs machen müßte.
Das sind nur die fehlenden Unit-Namen in der Database.Firebird.pas Datei, wer weiß wo mir da noch so alles was fehlt.
Meine Tokyo Version besitzt noch keine Extras, nur so wie es als Professional erhältlich ist bis auf PngComponents und Daniels Startpage.

haentschman 24. Mai 2018 10:45

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Ok...
1. Installiere dir die ZEOS Datenbank Komponenten. https://sourceforge.net/projects/zeoslib/

...dann melde dich wieder. :wink:

mkinzler 24. Mai 2018 10:51

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Liste der Anhänge anzeigen (Anzahl: 1)
QuickAndDirty Umbau nach FireDAC

KodeZwerg 24. Mai 2018 11:28

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Zitat:

Zitat von mkinzler (Beitrag 1402846)
QuickAndDirty Umbau nach FireDAC

Vielen Dank, das isses! Die Qualität kann ich nicht beurteilen aber kompilieren und Zugriff auf Test DB klappt!!
Also mein Problem ist hiermit gelöst, Danke!!!

haentschman 24. Mai 2018 11:38

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
:thumb:
Damit ist auch geklärt, daß man mit relativ wenigen Handgriffen eben mal den Datenbankzugriff tauscht.

@KodeZwerg
Zitat:

Also mein Problem ist hiermit gelöst, Danke!!!
...es wäre vieleicht besser gewesen, daß du dir die Zeos selbst installiert hast, um besser zu verstehen was alles zu einer Datenbank dazugehört. :?

KodeZwerg 24. Mai 2018 12:06

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
@haentschman: Da fehlt ein Tutorial was mal beschreibt was was ist. Ich höre hier mal AnyDAC dann UniDAC dort, FireDAC hab ich mal bei Emba was drüber gelesen, Maria Mongo Firebird DB, (non-)Sql nun Zeos, ich blicke da null durch was was macht und wofür man es braucht weswegen ich Deinem Rat nachkomme und mich mit Zeos beschäftigen werde. Auch durch andere Tutorials in Richtung DB verliere ich schnell den Überblick weil da teilweise nurnoch fachchinesisch gesprochen wird ohne chinesisch vorher zu entziffern. Hier bei Dir mit Aussage welche Unit was für Aufgaben hat, wie im groben die geforderten Tasks durchzuführen sind plus die Alternative Kommentare im Source, das ist für mich Nachvollziehbarer als woanders.

mkinzler 24. Mai 2018 12:29

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Es gibt verschiedene Zugriffsbibliotheken

MultiDB: UniDAC, FireDAC (ehemals AnyDAC), Zeos, ...
Datenbankspezifisch: IBDAC, UIB, ...

FireBird, Interbase, MySQL/MariaDB, Mongo, SQLite, MSSQL, Oracle, PosGres, ... sind verschiedene Datenbanksysteme

Auf die Datenbank-Tutorials des Delphi-Treffs wurdest Du ja schon mehrfach hingewiesen.

Vergelieche mal die Originalversion der Datei mit meinen Änderungen, dann sollte klar sein, was geändert wurde.

mkinzler 24. Mai 2018 12:30

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Zitat:

Damit ist auch geklärt, daß man mit relativ wenigen Handgriffen eben mal den Datenbankzugriff tauscht.
Wäre einfacher, wenn Klassen auf abreakterer Ebene Verwendung finden würden.

haentschman 24. Mai 2018 12:39

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Zitat:

Ich höre hier mal AnyDAC dann UniDAC dort, FireDAC hab ich mal bei Emba was drüber gelesen, Maria Mongo Firebird DB, (non-)Sql nun Zeos
...das sind alles Datenzugriffskomponenten für Datenbanken. Eine davon brauchst du. Die unterscheiden sich in der Regel in der Funktionsvielfalt und im Preis. Von kostenlos bis 800€ ist alles dabei. Die mit deinem Delphi mitgelieferten FireDAC sind ausschließlich Embedded benutzbar! Das heißt, das du nur auf Datenbanken die lokal auf dem Computer liegen, zugreifen kannst kannst.
Zeos ist kostenlos und auch mit Servern verschiedener Datenbanken verwendbar. Deshalb die Empfehlung. 8-)

KodeZwerg 24. Mai 2018 19:13

AW: [Tutorial] Laden / Speichern von Objekten in einer normalisierten Datenbank
 
Liste der Anhänge anzeigen (Anzahl: 1)
Da bin ich wieder mit frohe Kunde :-)

Zeos Installation endlich geschafft, Quervergleiche der verschiedenen Sources angeschaut, aus FireDAC nun Zeos, es funktioniert!

Eine Sache habe ich noch nicht herausgefunden, im Source ist eine Zeile
Delphi-Quellcode:
FConnection.OnError := DoError;
, wofür die steht ist mir schon klar aber ich finde bei Zeos nichts passendes, der Rest sollte hoffentlich so funktionieren wie geplant.

Anbei meine Zeos Adaption fürs Tutorial, wenn da ein erfahrener mal nachschaut ob mein Erstwerk als solches Okay ist oder ob ich grob was vergessen habe um Zeos zaubern zu lassen, das wäre toll.


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:37 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz