AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein mORMot: ORM und DocVariant kurz vorgestellt
Thema durchsuchen
Ansicht
Themen-Optionen

mORMot: ORM und DocVariant kurz vorgestellt

Ein Thema von mytbo · begonnen am 20. Jun 2022 · letzter Beitrag vom 27. Jun 2022
Antwort Antwort
mytbo

Registriert seit: 8. Jan 2007
461 Beiträge
 
#1

mORMot: ORM und DocVariant kurz vorgestellt

  Alt 20. Jun 2022, 23:32
Inspiriert durch diese Frage im Forum, möchte ich die Gelegenheit nutzen, einige mORMot Funktionen an einem Beispiel zu demonstrieren. Ziel ist es, so viel Funktionalität wie möglich mit nur wenigen Zeilen Quelltext zu präsentieren. Es geht hier um Konzepte, nicht um eine fertige Copy-Paste Lösung. Die enthaltenen Verweise zur Dokumentation verlinken zur aktuell verfügbaren mORMot1 Hilfe. Für das Beispiel wird mORMot2 verwendet. Die Namen für Klassen und Funktionen können sich leicht unterscheiden.

Im Anhang befindet sich der Sourcecode und das ausführbare Programm. Disclaimer: Der Sourcecode ist weder getestet noch optimiert. Er sollte mit Delphi ab Version 10.2 funktionieren. Die Benutzung der zur Verfügung gestellten Materialien erfolgt auf eigene Gefahr.

Die erstellte Klasse TImageResourceDB verwaltet Bilder und verwendet als Datengrab eine SQLite Datenbank. Das Interface ist sehr einfach gehalten und umfasst nur wenige Funktionen:
Delphi-Quellcode:
TImageResourceDB = class(TObject)
private
  FRestServer: TRestServerDB;
  function CreateModel: TOrmModel;
protected
  function LoadData(pmStream: TStream; const pmcRowID: TID): Boolean;
  function SaveData(const pmcImageData: RawBlob; const pmcTitle, pmcComment: String; const pmcMetaData: Variant; var pmvRowID: TID): Boolean;
public
  constructor Create(const pmcFileName: TFileName; const pmcPassword: RawUtf8 = '');
  destructor Destroy; override;
  class function InitDefaultMetaData(const pmcCreator, pmcLocation: RawUtf8; pmLatitude, pmLongitude: Double; pmDate: TDate; pmTime: TTime): Variant;
  function LoadImage(pmImage: TImage; const pmcRowID: TID): Boolean; overload;
  function LoadImage(pmImage: TImage; const pmcSearchPhrase: String; pmResultIDs: PIDDynArray = Nil): Boolean; overload;
  function LoadImage(pmImage: TImage; const pmcMetaFieldName: String; const pmcMetaFieldValue: Variant; pmResultIDs: PIDDynArray = Nil): Boolean; overload;
  function SaveImage(pmImage: TImage; const pmcTitle, pmcComment: String; const pmcMetaData: Variant; pmRowID: PID = Nil): Boolean; overload;
  function SaveImage(pmStream: TStream; const pmcTitle, pmcComment: String; const pmcMetaData: Variant; pmRowID: PID = Nil): Boolean; overload;
end;
Nichts Besonderes, mag man meinen. Mit den wenigen Zeile bekommt man:
  • Eine eingebettet (embedded) SQLite Datenbank, die optional AES verschlüsselt werden kann.
  • Mit dem integrierten ORM Aufgaben wie das Speichern und Lesen von Datensätzen erledigen.
  • Eine Volltextsuche über die Felder Title und Comment.
  • Ein Feld für Meta-Daten, das für jeden Datensatz verschiedene Felder enthalten und über SQL abgefragt werden kann.
  • Beschleunigung beim Speichern und Lesen der Grafik-Formate JPEG, PNG, GIF, TIFF.

Beschleunigung beim Speichern und Lesen von Bildern
Um den letzten Punkt gleich abzuhandeln, hierzu ein paar Benchmark-Wert aus der Anwendung ermittelt mit einem 2MB großen PNG-Bild:
Funktion / Unit NameVcl.Imaging.pngimagemormot.ui.gdiplus
SaveImage()
900 ms
25 ms
LoadImage()
70 ms
10 ms
Die Zahlen sprechen für sich. Bei einem Problem mit der Geschwindigkeit Folgendes probieren: Unit Vcl.Imaging.pngimage entfernen, danach Unit mormot.ui.gdiplus einbinden und die Funktion RegisterSynPictures aufrufen.

Embedded SQLite Datenbank
Um eine SQLite Datenbank statisch ins Programm einzubinden, muss nur die Unit mormot.db.raw.sqlite3.static hinzugefügt werden. Danach kann der Zugriff auf die SQLite3 Engine low-level, oder besser über eine TRest* Klasse erfolgen. Über Connection Klassen lassen sich auch andere Datenbanken anbinden. Es gibt Connections für die Frameworks ZEOS, FireDac/AnyDac, UniDac, ODBC, OleDB API und direkte Anbindungen für SQLite, PostgreSQL, Oracle OCI und MongoDB. Die Anbindung erfolgt über die schnellst mögliche Variante. Zum Beispiel verwendet ZEOS direkt ZDBC, anstatt über die Delphi DB Klassen zu gehen. Daraus ergibt sich eine deutliche Beschleunigung.

ORM initialisieren
Alle Klassen für das ORM müssen Nachfahre(n) der Klasse TOrm sein. Der Tabellenname in der Datenbank ergibt sich aus dem Klassennamen. Alle öffentlichen (published) Eigenschaften einer ORM Klasse werden als Feld in der Datenbank repräsentiert. Zusätzlich wird das Feld ID/RowID angelegt. Welche Feld-Typen möglich sind, ist in der Hilfe beschrieben. Die ORM Klassen werden in einem Model zusammengefasst. Das Model wird einer TRest* Klasse für den Zugriff übergeben. Eine Übersicht der vorhandenen TRest* Klassen und ihr Verwendungszweck ist in der Hilfe aufgelistet. Der eigentliche Quelltext ist nicht viel länger als die Beschreibung:
Delphi-Quellcode:
type
  TOrmFile = class(TOrm)
  ...
  published
    property Title: RawUTF8
      read FTitle write FTitle;
    property Comment: RawUtf8
      read FComment write FComment;
    property MetaData: Variant
      read FMetaData write FMetaData;
    ...
  end;

...
FRestServer := TRestServerDB.Create(TOrmModel.Create([TOrmFile, ...]), DBFileName, False, DBPassword);
FRestServer.Model.Owner := FRestServer;
FRestServer.DB.Synchronous := smFull;
FRestServer.DB.LockingMode := lmExclusive;
FRestServer.Server.CreateMissingTables(0, [itoNoAutoCreateGroups, itoNoAutoCreateUsers]);
Anmerkung: smFull ist mit Abstand der langsamste Modus, aber gewährleistet ein 100%iges ACID-Verhalten. In der Praxis ist smNormal ein guter Kompromiss aus Sicherheit und Geschwindigkeit. Im Beispiel besteht kein Grund für eine Authentifizierung, daher wird die automatische Erstellung der hierfür notwendigen Tabellen unterdrückt.

Aufgaben über das ORM erledigen
Eine Übersicht aller ORM Funktionen erhält man beim Blick in das IRestOrm Interface. Es steht eine Vielzahl von Möglichkeiten zur Auswahl. Die Anwendung ist sehr einfach. Das Hinzufügen eines Datensatzes geschieht wie folgt:
Delphi-Quellcode:
var
  ormFile: TOrmFile;
begin
  ormFile := TOrmFile.Create;
  try
    ormFile.Title := 'my first one';
    ormFile.Comment := 'Arnaud is the best';
    ...
    FRestServer.Server.Add(ormFile, True);
  finally
    ormFile.Free;
  end;
SQLite Volltextsuche
Um die Volltextsuche zu aktivieren, erstellt man eine eigene ORM Klasse, die von einer in mORMot vorhanden, spezialisierten Basisklassen (TOrmFts5/TOrmFts5Porter/TOrmFts5Unicode61) abstammt. In dieser Klasse werden die Felder der Datenklasse, die zum Suchen vorgesehen sind, wiederholt. Die Suche ist eine einfache SQL Abfrage:
Delphi-Quellcode:
var
  sqlWhere: RawUtf8;
  searchIDs: TIDDynArray;
begin
  sqlWhere := FormatUtf8('% MATCH ? ORDER BY rank DESC', ['SearchTable'], [SearchPhrase]);
  if FRestServer.Server.FTSMatch(TOrmFileSearch, sqlWhere, searchIDs) then
Anmerkung: Die Funktion FormatUtf8() ist der Delphi Format() Funktion ähnlich. Eine Zusatzfunktion ist, dass Argumente mit :(): umschlossen werden. Diese Markierung wird im ORM zur Optimierung verwendet.

Feld mit Meta-Daten
Ein Eigenschaftsfeld der Klasse vom Typ DocVariant wird im ORM als JSON gespeichert. Ein DocVariant ist eine beliebig komplexe Datenstruktur aus Objekt(en) und/oder Arrays, oder aus Kombinationen von beiden. WOW. Die DocVariant Syntax sieht für Pascal Entwickler etwas gewöhnungsbedürftig aus, weil es eher an eine Scriptsprache erinnert. Mehr dazu in der Hilfe nachlesen. Ein DocVariant lässt sich auf mehrere Arten erstellen. Eine Möglichkeit ist folgende:
Delphi-Quellcode:
var
  metaData: Variant;
begin
  TDocVariant.New(metaData);
  metaData.Number := 10;
  metaData.Creator := 'Thomas';
  metaData.Birthday := EncodeDate('Top Secret!');
In SQLite ab Version 3.38.0 lässt sich das mit folgender SQL Syntax abfragen:
Code:
Schema: SELECT * FROM File WHERE MetaData->>'$.Creator'='Thomas' ORDER BY ...
Zusammenfassung
mORMot ist gut dokumentiert. Die Hilfe umfasst mehr als 2500 Seiten. Davon enthalten die ersten ca. 650 Seiten einen sehr lesenswerten allgemeinen Teil, der Rest ist API Dokumentation. mORMot muss nicht in der IDE installierten werden! Es reicht aus, die entsprechenden Bibliothekspfade einzufügen. Bei neuen Anwendungen ist mORMot2 zu empfehlen. Hier der Link zum GitHub Repro. Es stehen viele Beispiele und ein freundliches Forum zur Verfügung. Wenn mehr Interesse an mORMot besteht, kann ich auch andere Teile in ähnlicher Weise kurz vorstellen.

Bis bald...
Thomas
Angehängte Dateien
Dateityp: zip TestSQLiteSource.zip (1,02 MB, 60x aufgerufen)
Dateityp: zip TestSQLiteExe.zip (2,22 MB, 41x aufgerufen)
  Mit Zitat antworten Zitat
Benutzerbild von Union
Union

Registriert seit: 18. Mär 2004
Ort: Luxembourg
3.487 Beiträge
 
Delphi 7 Enterprise
 
#2

AW: mORMot: ORM und DocVariant kurz vorgestellt

  Alt 21. Jun 2022, 10:43
Ein toller Beitrag Das hilft bestimmt vielen beim Einstieg. Denn 2500 Seiten Doku können einen auch erschlagen.
Ibi fas ubi proxima merces
sudo /Developer/Library/uninstall-devtools --mode=all
  Mit Zitat antworten Zitat
Arkar

Registriert seit: 1. Jul 2015
Ort: Bamberg
11 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: mORMot: ORM und DocVariant kurz vorgestellt

  Alt 26. Jun 2022, 02:53
Eine PDF erstellen mit Tabellen wäre auch mal was xD
Sven
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.110 Beiträge
 
Delphi 10 Seattle Enterprise
 
#4

AW: mORMot: ORM und DocVariant kurz vorgestellt

  Alt 26. Jun 2022, 07:58
Ich habe mich vor mORMot bislang immer gedrückt, auch wenn ein paar mal ein paar nützliche Dinge für mich drin gewesen wären.

Vielleicht lag ich falsch, aber ich habe es als eine riesige Bibliothek, wo jede Unit immer von zwei Dutzend anderen Mormot-Units abhängt, in Erinnerung. Dann noch mit jede Menge obskurem Code in initialization/finalization-Abschnitten und ich verstehe überhaupt nicht, wo sich das alles einklinkt. Das hat mich zu sehr an die JCL erinnert und ich bin weggelaufen.

Ist das immer noch so? War mein damaliger Eindruck falsch?
  Mit Zitat antworten Zitat
mytbo

Registriert seit: 8. Jan 2007
461 Beiträge
 
#5

AW: mORMot: ORM und DocVariant kurz vorgestellt

  Alt 26. Jun 2022, 22:46
Ist das immer noch so? War mein damaliger Eindruck falsch?
Die Frage ist nicht einfach zu beantworten, weil ich nicht weiß, ob du deine Erfahrungen mit mORMot Version 1 oder 2 gemacht hast. Allgemein: Ja, mORMot ist riesig, aber in seiner Gesamtheit ein wunderbares Werk der Programmierkunst. Die gesamte Umsetzung von mORMot1, vor allem die Formatierung des Quelltextes, war für mich eine Herausforderung. Ich musste mir jede Funktion zweimal ansehen und den Quelltext im Geiste mehrfach umformatieren. Das lag an der evolutionären Entstehung der Bibliothek, wahrscheinlich auch daran, dass Arnaud Performance einen besonders hohen Stellenwert einräumt und dem vieles unterordnet. mORMot2 ist sehr gut strukturiert und die Richtlinien für die Formatierung des Quelltextes orientieren sich am Gewohnten.

Was mORMot schon immer ausgezeichnet hat, ist der "sowohl - als auch" Gedanke. In der Anfangszeit meiner Nutzung, ab Ende 2009, habe ich mORMot für einige Jahre als Ergänzung und später als Ersatz der JCL eingesetzt. Erst 2013 wurde von mir der erste Server realisiert. Den Gedanken, mORMot als riesige Funktionsbibliothek einzusetzen, würde ich deshalb nicht als Fehler erachten. Ziel ist es doch, die Anzahl der Abhängigkeiten zu externen Bibliotheken zu reduzieren. Das kann man IMHO nur durch hochwertige multifunktionale Bibliotheken erreichen. Die Anzahl der einzubindenden Units einer Bibliothek spielt dabei für mich keine Rolle. Die mORMot2 Units haben ein stringentes Namensschema. Man findet sich schnell zurecht.

mORMot hat viele Funktionen und mehr als 74M automatisierte Tests. Sich Stück für Stück einzuarbeiten halte ich für den Weg, der am schnellsten Erfolg verspricht. Steht man vor einer konkreten Aufgabe und glaubt, mORMot in wenigen Stunden oder Tagen zu erlernen, wird man wahrscheinlich scheitern.

Bis bald...
Thomas
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.110 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

AW: mORMot: ORM und DocVariant kurz vorgestellt

  Alt 27. Jun 2022, 09:03
Alles klar, wahrscheinlich wird das noch "Version 1" gewesen sein, damals.
Mir ging es nicht um die Anzahl der Units, sondern dass einfach nicht überschaubar war, was da eigentlich abgeht, weshalb kann eine Routine nicht mit einer mit einer normalen StringList oder String-Array arbeiten, sondern erfindet sich wieder einen eigenen Typ, der nur in dieser Bibliothek existiert? Solche Dinge halt...

und mehr als 74M automatisierte Tests
Du meintest hoffentlich 74.000 und nicht 74.000.000? Hoffentlich, denn sonst hätte ich Angst.

Wenn ich eines Tages mal Zeit habe schaue ich mir das bestimmt mal näher an. Vielen Dank für die ausführliche Erklärung.
  Mit Zitat antworten Zitat
mytbo

Registriert seit: 8. Jan 2007
461 Beiträge
 
#7

AW: mORMot: ORM und DocVariant kurz vorgestellt

  Alt 27. Jun 2022, 10:50
und mehr als 74M automatisierte Tests
Du meintest hoffentlich 74.000 und nicht 74.000.000? Hoffentlich, denn sonst hätte ich Angst.
Aktuell: Total assertions failed for all test suits: 0 / 74.197.472
Mich beruhigt das.

Bis bald...
Thomas
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:14 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