From SQL to ORM
Arnaud Bouchez
June 2015
From SQL to ORM
SQL
NoSQL
ORM
ODM
practice
From SQL to ORM
June 2015
SQL
De-Facto standard for data manipulation
Schema-based
Relational-based
ACID by transactions
Time proven and efficient
Almost standard
From SQL to ORM
June 2015
SQL
De-Facto standard for data manipulation
Schema-based
Relational-based
From SQL to ORM
June 2015
Not Only SQL
Two main families of NoSQL databases:
Aggregate-oriented databases
Graph-oriented databases
Martin Fowler
From SQL to ORM
June 2015
Not Only SQL
Graph Database
Store data by their relations / associations
From SQL to ORM
June 2015
Not Only SQL
Aggregate
is a collection of data
that we interact with
as a unit
forms the boundaries
for ACID operations
in a given model
(Domain-Driven Design modeling)
From SQL to ORM
June 2015
Not Only SQL
Aggregate Database families
Document-based
e.g. MongoDB, CouchDB
Key/Value
e.g. Redis
Column family
e.g. Cassandra
From SQL to ORM
June 2015
Not Only SQL
Are designed to scale for the web
Examples: Google farms, Amazon
Should not be used as scaling RDBMS
Can be schema-less
For document-based and key/value
or column-driven
Can be BLOB storage
From SQL to ORM
June 2015
Not Only SQL
RBMS stores data per table
JOIN the references to get the aggregate
From SQL to ORM
June 2015
Not Only SQL
NoSQL stores aggregate as documents
Whole data is embedded
From SQL to ORM
June 2015
Not Only SQL
NoSQL stores aggregate as documents
Whole data is embedded
(boundaries for ACID behavior)
From SQL to ORM
June 2015
Not Only SQL
Data modeling
From SQL to ORM
June 2015
Not Only SQL
Data modeling
SQL NoSQL
Normalization Denormalization
Consistency Duplicated data
Transactions Document ACID
Vertical scaling Horizontal scaling
From SQL to ORM
June 2015
Not Only SQL
SQL > NoSQL
Ubiquitous SQL
Easy vertical scaling
Data size (avoid duplicates and with no schema)
Data is stored once, therefore consistent
Complex ACID statements
Aggregation functions (depends)
From SQL to ORM
June 2015
Not Only SQL
From SQL to ORM
June 2015
Not Only SQL
NoSQL > SQL
Uncoupled data: horizontal scaling
Schema-less: cleaner evolution
Straight-To-ODM
Version management (e.g. CouchDB)
Graph storage (e.g. Redis)
From SQL to ORM
June 2015
Object Relational Mapping (ORM)
ORM
gives a set of methods (CRUD)
to ease high-level objects persistence
into an RDBMS
via mapping
From SQL to ORM
June 2015
Object Relational Mapping (ORM)
Since decades
Classes
are the root of our OOP model
RDBMS is (the) proven way of storage
Some kind of "glue" is needed to let class
properties be saved into one or several tables
From SQL to ORM
June 2015
Object Relational Mapping (ORM)
In fact
Classes
are accessed via Delphi/Java/C# code
RDBMS is accessed via SQL
SQL by itself is a full programming language
With diverse flavors (e.g. data types)
Difficult to switch the logic
Error prone, and difficult to maintain
From SQL to ORM
June 2015
Object Relational Mapping (ORM)
Sometimes, object object
therewill be nothing better instance instance
than a tuned SQL statement CRUD
operations
But most of the time, SQL ORM
You
need just to perform mapping
some basic CRUD operations
(Create Retrieve Update Delete) RDBMS SQL
RDBMS
From SQL to ORM
June 2015
Object Relational Mapping (ORM)
myObject.Value := 10;
myContext.Update(myObject);
UPDATE OBJTABLE SET …
01010101001110011111
From SQL to ORM
June 2015
Object Relational Mapping (ORM)
Benefits No magic bullet
Stay at OOP level Hard task
Manage SQL flavors Hidden process
Persistence Ignorance Legacy (tuned) SQL
Optimize SQL Performance cost
Cache
From SQL to ORM
June 2015
Object Relational Mapping (ORM)
Benefits No magic bullet
Stay at OOP level Hard task
Manage SQL flavors Hidden process
Persistence Ignorance Legacy (tuned) SQL
Optimize SQL Performance cost
Cache (or not)
From SQL to ORM
June 2015
Object Relational Mapping (ORM)
ORM
Mapping may be created:
class type data model
Code-first
Objects are defined,
object instance RDBMS
then persisted (dehydrated)
Usually the best for a new project
Model-first
Froman (existing) database model
Sometimes difficult to work with legacy structures
From SQL to ORM
June 2015
Object Relational Mapping (ORM)
Mapping may be defined:
by configuration
via code (attributes or fluent interface)
via external files (XML/JSON)
by convention
from object layout
from database layout
From SQL to ORM
June 2015
Object Relational Mapping (ORM)
Objects may be:
Any business class (PODO)
Eases integration with existing code
But may pollute the class (attributes)
Inherit from a common class
Geta shared behavior
Tend to enforce DDD’s persistence agnosticity
From SQL to ORM
June 2015
Object Relational Mapping (ORM)
ORM advantages
Compile time naming and types check
(strong types and names)
One language to rule all your logic
(no mix with SQL nor LINQ syntax)
Database abstraction
(the ORM knows all dialects, and can switch)
Able to cache the statements and the values
You still can write hand-tuned SQL if needed
From SQL to ORM
June 2015
Object Relational Mapping (ORM)
Don't think about…
tables with data types (varchar/number...),
but objects with high level types
Master/Detail,
but logical units (your aggregates)
writing SQL,
but writing your business code
"How will I store it?",
but "Which data do I need?".
From SQL to ORM
June 2015
Object Document Mapping (ODM)
Aggregate = all data in a given context
Such documents do map our objects!
From SQL to ORM
June 2015
Object Document Mapping (ODM)
CRUD operation on Aggregates documents
mORMot’s ODM is able to share code with ORM
From SQL to ORM
June 2015
mORMot’s RESTful ORM/ODM
From SQL to ORM
June 2015
mORMot’s RESTful ORM/ODM
mORMot’s client-server RESTful ORM/ODM
code-first
or model-first ORM/ODM
ORM for RDBMS: generates SQL
ODM for NoSQL: handles documents and queries
convention (TSQLRecord) over configuration
can be consumed via REST
over HTTP or WebSockets, via JSON transmission
or locally, on the server side, e.g. in SOA services
From SQL to ORM
June 2015
mORMot’s RESTful ORM/ODM
UI Components UI UI UI 1 UI 2 (web)
MVC MVC/MVVM MVC
RAD code mapping
binding binding binding
DataBase Delphi classes ORM Client 1 Client 2
Secure
Handwritten Generated
protocol
SQL SQL
(REST)
DataBase Database Server
Persistence
layer
ORM
Generated
SQL
Database
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Defining the object
/// some enumeration
// - will be written as 'Female' or 'Male' in our UI Grid
// - will be stored as its ordinal value, i.e. 0 for sFemale, 1 for sMale
// - as you can see, ladies come first, here
TSex = (sFemale, sMale);
/// table used for the Babies queries
TSQLBaby = class(TSQLRecord)
private
fName: RawUTF8;
fAddress: RawUTF8;
fBirthDate: TDateTime;
fSex: TSex;
published
property Name: RawUTF8 read fName write fName;
property Address: RawUTF8 read fAddress write fAddress;
property BirthDate: TDateTime read fBirthDate write fBirthDate;
property Sex: TSex read fSex write fSex;
end;
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Defining the Model and the Server:
Model := TSQLModel.Create([TSQLBaby],'rootURI');
ServerDB := TSQLRestServerDB.Create(Model,'data.db'),true);
ServerDB.CreateMissingTables;
Server := TSQLHttpServer.Create('8080',ServerDB);
Defining the Model and the Client:
Model := TSQLModel.Create([TSQLBaby],'rootURI');
Client := TSQLHttpClient.Create(Server,'8080', Model);
Both will now communicate e.g. over
http://server:8080/rootURI/Baby
From SQL to ORM
June 2015
mORMot’s RESTful ORM
var Baby: TSQLBaby;
ID: integer;
begin
// create a new record, since Smith, Jr was just born
Baby := TSQLBaby.Create;
try
Baby.Name := 'Smith';
Baby.Address := 'New York City';
Baby.BirthDate := Now;
Baby.Sex := sMale;
ID := Client.Add(Baby);
finally
Baby.Free;
end;
// update record data
Baby := TSQLBaby.Create(Client,ID);
try
assert(Baby.Name='Smith');
Baby.Name := 'Smeeth';
Client.Update(Baby);
finally
Baby.Free;
end;
// retrieve record data
Baby := TSQLBaby.Create;
try
Client.Retrieve(ID,Baby);
// we may have written: Baby := TSQLBaby.Create(Client,ID);
assert(Baby.Name='Smeeth');
finally
Baby.Free;
end;
// delete the created record
Client.Delete(TSQLBaby,ID);
end;
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Returning several objects
aMale := TSQLBaby.CreateAndFillPrepare(Client,
'Name LIKE ? AND Sex = ?',['A%',ord(sMale)]);
try
while aMale.FillOne do
DoSomethingWith(aMale);
finally
aMale.Free;
end;
Results are transmitted as a JSON array
Results can be cached at client or server side
Only one object instance is allocated and filled
Full WHERE clause of the SELECT is at hand
See also function TSQLRest.RetrieveList(): TObjectList
From SQL to ORM
June 2015
mORMot’s RESTful ORM
JSON transmission layout
Expanded / standard (AJAX)
JSON array of JSON objects
[{"ID":1},{"ID":2},{"ID":3},{"ID":4},{"ID":5},{"ID":6},{"ID":7}]
Non expanded / faster (Delphi)
JSON object of JSON array of values, first row being idents
{"fieldCount":1,"values":["ID",1,2,3,4,5,6,7]}
In mORMot, all JSON content is parsed and processed in-place,
then directly mapped to UTF-8 structures.
From SQL to ORM
June 2015
mORMot’s RESTful ORM
« One to one » / « One to many » cardinality
TSQLMyFileInfo = class(TSQLRecord)
private
FMyFileDate: TDateTime;
FMyFileSize: Int64;
published
property MyFileDate: TDateTime read FMyFileDate write FMyFileDate;
property MyFileSize: Int64 read FMyFileSize write FMyFileSize;
end;
TSQLMyFile = class(TSQLRecord)
private
FSecondOne: TSQLMyFileInfo;
FFirstOne: TSQLMyFileInfo;
FMyFileName: RawUTF8;
published
property MyFileName: RawUTF8 read FMyFileName write FMyFileName;
property FirstOne: TSQLMyFileInfo read FFirstOne write FFirstOne;
property SecondOne: TSQLMyFileInfo read FSecondOne write FSecondOne;
end;
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Automatic JOINed query
Atconstructor level
With nested instances memory management
var MyFile: TSQLMyFile;
begin
MyFile := TSQLMyFile.CreateJoined(Client,aMyFileID);
try
// here MyFile.FirstOne and MyFile.SecondOne are true instances
// and have already retrieved from the database by the constructor
// so you can safely access MyFile.FirstOne.MyFileDate or MyFile.SecondOne.MyFileSize here!
finally
MyFile.Free; // will release also MyFile.FirstOne and MyFile.SecondOne
end;
end;
See also CreateAndFillPrepareJoined()
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Server or Client Cache
Disabledby default
May be activated
For a given table
For a given set of IDs
On a given TSQLRest
In
conjunction with
Server DB cache
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Object Time Machine
Database.TrackChanges([TSQLInvoice]);
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Object Time Machine
Database.TrackChanges([TSQLInvoice]);
aInvoice := TSQLInvoice.Create;
aHist := TSQLRecordHistory.CreateHistory(aClient,TSQLInvoice,400);
try
writeln('History Count: ',aHist.HistoryCount);
for i := 0 to aHist.HistoryCount-1 do begin
aHist.HistoryGet(i,aEvent,aTimeStamp,aInvoice);
writeln('Event: ',ord(aEvent))^);
writeln('TimeStamp: ',TTimeLogBits(aTimeStamp).ToText);
writeln('Identifier: ',aInvoice.Number);
end;
...
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Master/Slave Replication
TSQLRecordPeopleVersioned = class(TSQLRecordPeople)
protected
fFirstName: RawUTF8;
fLastName: RawUTF8;
fVersion: TRecordVersion;
published
property FirstName: RawUTF8 read fFirstName write fFirstName;
property LastName: RawUTF8 read fLastName write fLastName;
property Version: TRecordVersion read fVersion write fVersion;
end;
Hidden monotonic version number will be maintained
to monitor Add/Update/Delete actions
Deletions stored in a separated table
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Master/Slave Replication
MasterServer := TSQLRestServerDB.Create(MasterModel,'master.db3');
HttpMasterServer := TSQLHttpServer.Create('8888',[MasterServer]);
MasterClient := TSQLHttpClientHTTP.Create(
'127.0.0.1',HTTP_DEFAULTPORT,MasterModel);
SlaveServer := TSQLRestServerDB.Create(SlaveModel,'slave.db3');
SlaveServer.RecordVersionSynchronizeSlave(
TSQLRecordPeopleVersioned,MasterClient);
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Master
Master/Slave Replication MasterServer
(MasterModel)
MasterServer := TSQLRestServerDB.Create( HTTP
MasterModel,'master.db3'); Slave
HttpMasterServer := TSQLHttpServer.Create(
'8888',[MasterServer]); MasterClient
master.db3
(MasterModel)
MasterClient := TSQLHttpClientHTTP.Create( On Demand
'127.0.0.1',HTTP_DEFAULTPORT,MasterModel); Replication
SlaveServer := TSQLRestServerDB.Create( SlaveServer
(SlaveModel)
SlaveModel,'slave.db3');
SlaveServer.RecordVersionSynchronizeSlave(
slave.db3
TSQLRecordPeopleVersioned,MasterClient);
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Master/Slave Real-Time Replication
Push ORM modifications over WebSockets
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Master/Slave Real-Time Replication
MasterServer := TSQLRestServerDB.Create(MasterModel,'master.db3');
HttpMasterServer :=
TSQLHttpServer.Create('8888',[MasterServer],'+',useBidirSocket);
HttpMasterServer.WebSocketsEnable(Server,'PrivateAESEncryptionKey');
MasterServer.RecordVersionSynchronizeMasterStart;
MasterClient := TSQLHttpClientWebSockets.Create(
'127.0.0.1',HTTP_DEFAULTPORT,MasterModel);
MasterClient.WebSocketsUpgrade('PrivateAESEncryptionKey');
SlaveServer := TSQLRestServerDB.Create(SlaveModel,'slave.db3');
SlaveServer.RecordVersionSynchronizeSlaveStart(
TSQLRecordPeopleVersioned,MasterClient);
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Master/Slave Real-Time Replication
Master
MasterServer
SlaveServer := TSQLRestServerDB.Create( (MasterModel)
SlaveModel,'slave.db3');
WebSockets
TCP/IP
SlaveServer.RecordVersionSynchronizeSlaveStart( Slave
TSQLRecordPeopleVersioned,MasterClient); master.db3
MasterClient
(MasterModel)
Replication
SlaveServer
(SlaveModel)
slave.db3
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Persistence over External RDMS
SynDB optimized data access layer
SynDB
DB.pas
ZDBC ODBC OleDB Oracle SQLite3
TDataset
FireDAC
NexusDB BDE DBExpress UniDAC
AnyDAC
From SQL to ORM
June 2015
mORMot’s RESTful ORM
SynDB classes
By-pass the DB.pas unit
avoid TDataSet bottleneck, work with Starter Edition
… but can still use it (e.g. FireDAC)
Simple KISS designed API
less data types, interface-based
Statement cache
Array binding (bulk insert / batch mode)
Direct JSON generation
Optional remote access via HTTP
From SQL to ORM
June 2015
mORMot’s RESTful ORM
SynDB integration with ORM
TSQLRestServerDB.Add
external
internal
table
table
REST
TSQLRestServerDB.EngineAdd TSQLRestServerStaticExternal.EngineAdd
INSERT INTO... INSERT INTO...
TSQLRequest ISQLDBStatement
internal engine ODBC/ZDBC/OleDB...
SQlite3 engine External DB client
SQLite3 file External DB server
From SQL to ORM
June 2015
mORMot’s RESTful ORM
SQLite3 Virtual Tables
From SQL to ORM
June 2015
mORMot’s RESTful ORM
SQLite3 Virtual Tables
Mapping of external field names
JOIN several external databases
Very slight performance penalty
Access TObjectList instances
Access NoSQL databases
By-passed if possible
Full SQL-92 engine at hand
From SQL to ORM
June 2015
mORMot’s RESTful ORM
SQLite3 Virtual Tables
mORMot
ORM
direct
direct SQLite3 direct
virtual
TObjectList External DB
DB.pas
direct
TDataSet
Oracle SQLite3 ODBC OleDB ZDBC FireDAC AnyDAC UniDAC BDE DBExpress NexusDB
From SQL to ORM
June 2015
mORMot’s RESTful ORM
From SQL to ORM
June 2015
mORMot’s RESTful ORM
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Defining the object
type
TSQLRecordPeopleExt = class(TSQLRecord) ID : integer ID : INTEGER
private
fData: TSQLRawBlob; Data : TSQLRawBlob Data : BLOB
fFirstName: RawUTF8; FirstName : RawUTF8 FirstName : NVARCHAR(40)
fLastName: RawUTF8; LastName : RawUTF8 LastName : NVARCHAR(40)
fYearOfBirth: integer;
YearOfBirth : integer YearOfBirth : INTEGER
fYearOfDeath: word;
fLastChange: TModTime; YearOfDeath : word YearOfDeath : INTEGER
fCreatedAt: TCreateTime;
published
property FirstName: RawUTF8 index 40 read fFirstName write fFirstName;
property LastName: RawUTF8 index 40 read fLastName write fLastName;
property Data: TSQLRawBlob read fData write fData;
property YearOfBirth: integer read fYearOfBirth write fYearOfBirth;
property YearOfDeath: word read fYearOfDeath write fYearOfDeath;
property LastChange: TModTime read fLastChange write fLastChange;
property CreatedAt: TCreateTime read fCreatedAt write fCreatedAt;
end;
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Defining the Model and the Server:
Props := TOleDBMSSQLConnectionProperties.Create(
'.\SQLEXPRESS','AdventureWorks2008R2','','');
Model := TSQLModel.Create([TSQLRecordPeopleExt],'root');
VirtualTableExternalRegister(Model,TSQLRecordPeopleExt,Props,'Test.People');
ServerDB := TSQLRestServerDB.Create(Model,'application.db'),true);
ServerDB.CreateMissingTables;
Server := TSQLHttpServer.Create('8080',ServerDB);
Defining the Model and the Client:
Model := TSQLModel.Create([TSQLRecordPeopleExt],'root');
Client := TSQLHttpClient.Create(Server,'8080', Model);
Both will now communicate e.g. over
http://server:8080/root/PeopleExt
From SQL to ORM
June 2015
mORMot’s RESTful ORM
Refining the mapping Model on the Server:
Props := TOleDBMSSQLConnectionProperties.Create(
'.\SQLEXPRESS','AdventureWorks2008R2','','');
Model := TSQLModel.Create([TSQLRecordPeopleExt],'root');
VirtualTableExternalRegister(Model,TSQLRecordPeopleExt,Props,'Test.People');
ID : integer Key : INTEGER
Model.Props[TSQLRecordPeopleExt].ExternalDB. Data : TSQLRawBlob Data : BLOB
MapField('ID','Key'). FirstName : RawUTF8 FirstName : NVARCHAR(40)
MapField('YearOfDeath','YOD'); LastName : RawUTF8 LastName : NVARCHAR(40)
YearOfBirth : integer YearOfBirth : INTEGER
YearOfDeath : word YOD : INTEGER
ServerDB := TSQLRestServerDB.Create(Model,'application.db'),true);
ServerDB.CreateMissingTables;
Server := TSQLHttpServer.Create('8080',ServerDB);
From SQL to ORM
June 2015
mORMot’s RESTful ORM/ODM
Data Sharding / Denormalization pattern
Storethe whole aggregate as once
Without JOIN
From ORM to ODM
Object Relational Mapping (ORM)
Object Document Mapping (ODM)
From SQL to ORM
June 2015
mORMot’s RESTful ODM
Object Document Mapping
ODM over regular RDBMS
NoSQL storage via TDocVariant property
Stored as JSON, handled as a variant
ODM over dedicated NoSQL engine
TObjectList
MongoDB direct access
From SQL to ORM
June 2015
mORMot’s RESTful ODM
NoSQL storage via TDocVariant property
TSQLRecordData = class(TSQLRecord)
private
fName: RawUTF8;
fData: variant;
public
published
property Name: RawUTF8 read fTest write fTest stored AS_UNIQUE;
property Data: variant read fData write fData;
end;
Document is indexed:
by TSQLRecord.ID: integer
by Name: RawUTF8
From SQL to ORM
June 2015
mORMot’s RESTful ODM
NoSQL storage via TDocVariant custom type
TSQLRecordData = class(TSQLRecord)
private
fName: RawUTF8;
fData: variant;
public
published
property Name: RawUTF8 read fTest write fTest stored AS_UNIQUE;
property Data: variant read fData write fData;
end;
Data: variant will store any document
As JSON in the RDBMS
Accessed via late-binding in Delphi code
From SQL to ORM
June 2015
mORMot’s RESTful ODM
Data: variant will store a TDocVariant
Schema-less data
{ name : "Joe", x : 3.3, y : [1,2,3] }
{ name : "Kate", x : "abc" }
{ q : 456 }
Real-world evolving data
{ name : "Joe", age : 30, interests : "football" }
{ name : "Kate", age : 25 }
From SQL to ORM
June 2015
mORMot’s RESTful ODM
var aRec: TSQLRecordData;
aID: integer;
begin
// initialization of one record
aRec := TSQLRecordData.Create;
aRec.Name := 'Joe'; // one unique key
aRec.data := _JSONFast('{name:"Joe",age:30}'); // create a TDocVariant
// or we can use this overloaded constructor for simple fields
aRec := TSQLRecordData.Create(['Joe',_ObjFast(['name','Joe','age',30])]);
// now we can play with the data, e.g. via late-binding:
writeln(aRec.Name); // will write 'Joe'
writeln(aRec.Data); // will write '{"name":"Joe","age":30}' (auto-converted to JSON string)
aRec.Data.age := aRec.Data.age+1; // one year older
aRec.Data.interests := 'football'; // add a property to the schema
aID := aClient.Add(aRec); // will store {"name":"Joe","age":31,"interests":"footbal"}
aRec.Free;
// now we can retrieve the data either via the aID created integer, or via Name='Joe'
end;
From SQL to ORM
June 2015
mORMot’s RESTful ODM
NoSQL Engines
TObjectList - TSQLRestStorageInMemory
Fast in-memory storage
Supports hash indexes on (unique) properties
Binary or JSON persistence as file
Could embed some unpersisted live process
MongoDB
SynMongoDB.pasfor direct access
mORMotMongoDB.pas for ODM integration
From SQL to ORM
June 2015
mORMot’s RESTful ODM
SynMongoDB.pas
BSON types, including BLOB, ObjectID, date/time…
TBSONVariant with late-binding
(Extended) JSON as input or output
Document-level access
Bulk document insertion
Could be used standalone, without the ODM
From SQL to ORM
June 2015
mORMot’s RESTful ODM
mORMotMongoDB.pas
Full
integration with mORMot’s RESTful ORM
Share the same logic code with RDBMS
Just one line to change on the server side
Same exact RESTful business code
On-the-fly query translation
SQL WHERE clause translated to MongoDB query object
Including aggregate functions, limits, offset
BATCH support, low memory use, data marshalling
From SQL to ORM
June 2015
mORMot’s RESTful ODM
uses SynMongoDB, mORMotMongoDB;
Model := TSQLModel.Create([TSQLORM]);
Server := TSQLRestServerDB.Create(Model,nil,':memory:');
MongoClient := TMongoClient.Create('localhost',27017);
MongoDatabase := MongoClient.Database[DB_NAME];
StaticMongoDBRegister(TSQLORM,Server,MongoDatabase);
Server.CreateMissingTables;
… usual code
From SQL to ORM
June 2015
mORMot’s RESTful ORM/ODM
BATCH process // start the BATCH sequence
Check(ClientDist.BatchStart(TSQLRecordPeople,5000));
ORM CRUD operation // delete some elements
for i := 0 to n-1 do
Check(ClientDist.BatchDelete(IntArray[i])=i);
In-process // update some elements
no latency nupd := 0;
for i := 0 to aStatic.Count-1 do
if i and 7<>0 then
ORM HTTP Client begin // not yet deleted in BATCH mode
Check(ClientDist.Retrieve(aStatic.ID[i],V));
V.YearOfBirth := 1800+nupd;
Internet Check(ClientDist.BatchUpdate(V)=nupd+n);
100 ms latency inc(nupd);
end;
// add some elements
ORM HTTP Server V.LastName := 'New';
for i := 0 to 1000 do
begin
In-process V.FirstName := RandomUTF8(10);
V.YearOfBirth := i+1000;
no latency
Check(ClientDist.BatchAdd(V,true)=n+nupd+i);
end;
// send the BATCH sequences to the server
ORM database core Check(ClientDist.BatchSend(Results)=200);
From SQL to ORM
June 2015
mORMot’s RESTful ORM/ODM
BATCH process
Truly ACID, even with several RDBMS backends
Automatic transaction handling
Avoids slow Client-Server roundtrips
Unit-Of-Work pattern, even on Server side
Optimized SQL
Parameter Array Binding
e.g. Oracle, ZDBC, FireDAC
Multiple INSERT statement
Depending on the database dialect
Re-use of prepared statements
NoSQL (MongoDB) bulk insertion
From SQL to ORM
June 2015
mORMot’s RESTful ORM/ODM
Security
Rooted on framework’s authentication(s)
Secured by SHA-256 challenge to avoid MIM / replay
Users belong to groups
Per-table CRUD access right for each group
Optional JSON compression and encryption
Over standard HTTP / HTTPS wire
From SQL to ORM
June 2015
mORMot’s RESTful ORM/ODM
RESTful Client-Server
In-process
Stand-alone client, fast server-side access
Named pipes or GDI messages
Stand-alone client, fast server-side access
HTTP/1.1 via kernel-mode http.sys API
Part of the OS since Windows XP SP2, used by IIS and WCF
Kernel-mode execution, IOCP driven
System-wide URI registration: share root and port
Socket-based server is also available, e.g. under Linux
Optional query/answer REST emulation over WebSockets
From SQL to ORM
June 2015
mORMot’s RESTful ORM/ODM
Cross-platform Clients
Generated client code using Mustache templates
Delphi:Windows, MacOS, Android, iOS
FPC: Windows, MacOS, Android, iOS, Linux, …
(Cross)Kylix: Linux
SmartMobileStudio: Ajax / HTML5
Featuring almost all framework abilities
JSON, security, TSQLRest, TSQLRestBatch
From SQL to ORM
June 2015
From SQL to ORM
June 2015