![]() |
mORMot: ORM und DocVariant kurz vorgestellt
Liste der Anhänge anzeigen (Anzahl: 2)
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
![]() 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:
Nichts Besonderes, mag man meinen. Mit den wenigen Zeile bekommt man:
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;
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:
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 ![]() ![]()
Delphi-Quellcode:
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.
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]); 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:
SQLite Volltextsuche
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; 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:
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.
var
sqlWhere: RawUtf8; searchIDs: TIDDynArray; begin sqlWhere := FormatUtf8('% MATCH ? ORDER BY rank DESC', ['SearchTable'], [SearchPhrase]); if FRestServer.Server.FTSMatch(TOrmFileSearch, sqlWhere, searchIDs) then 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 ![]()
Delphi-Quellcode:
In SQLite ab Version 3.38.0 lässt sich das mit folgender SQL Syntax abfragen:
var
metaData: Variant; begin TDocVariant.New(metaData); metaData.Number := 10; metaData.Creator := 'Thomas'; metaData.Birthday := EncodeDate('Top Secret!');
Code:
Zusammenfassung
Schema: SELECT * FROM File WHERE MetaData->>'$.Creator'='Thomas' ORDER BY ...
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 ![]() ![]() Bis bald... Thomas |
AW: mORMot: ORM und DocVariant kurz vorgestellt
Ein toller Beitrag :thumb: Das hilft bestimmt vielen beim Einstieg. Denn 2500 Seiten Doku können einen auch erschlagen.
|
AW: mORMot: ORM und DocVariant kurz vorgestellt
Eine PDF erstellen mit Tabellen wäre auch mal was xD
|
AW: mORMot: ORM und DocVariant kurz vorgestellt
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? |
AW: mORMot: ORM und DocVariant kurz vorgestellt
Zitat:
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 |
AW: mORMot: ORM und DocVariant kurz vorgestellt
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... Zitat:
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. |
AW: mORMot: ORM und DocVariant kurz vorgestellt
Zitat:
Mich beruhigt das. :wink: Bis bald... Thomas |
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:59 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz