A3 From SQL To ORM
A3 From SQL To ORM
Arnaud Bouchez
June 2015
From SQL to ORM
SQL
NoSQL
ORM
ODM
practice
Relational-based
ACID by transactions
Time proven and efficient
Almost standard
Relational-based
Martin Fowler
Document-based
e.g. MongoDB, CouchDB
Key/Value
e.g. Redis
Column family
e.g. Cassandra
Can be schema-less
For document-based and key/value
or column-driven
SQL NoSQL
Normalization Denormalization
Consistency Duplicated data
Transactions Document ACID
Vertical scaling Horizontal scaling
Straight-To-ODM
ORM
gives a set of methods (CRUD)
to ease high-level objects persistence
into an RDBMS
via mapping
Since decades
Classes
are the root of our OOP model
RDBMS is (the) proven way of storage
In fact
Classes
are accessed via Delphi/Java/C# code
RDBMS is accessed via SQL
You
need just to perform mapping
some basic CRUD operations
(Create Retrieve Update Delete) RDBMS SQL
RDBMS
myObject.Value := 10;
myContext.Update(myObject);
01010101001110011111
Model-first
Froman (existing) database model
Sometimes difficult to work with legacy structures
by configuration
via code (attributes or fluent interface)
via external files (XML/JSON)
by convention
from object layout
from database layout
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
Secure
Handwritten Generated
protocol
SQL SQL
(REST)
Persistence
layer
ORM
Generated
SQL
Database
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;
In
conjunction with
Server DB cache
MasterClient := TSQLHttpClientHTTP.Create(
'127.0.0.1',HTTP_DEFAULTPORT,MasterModel);
SlaveServer := TSQLRestServerDB.Create(SlaveModel,'slave.db3');
SlaveServer.RecordVersionSynchronizeSlave(
TSQLRecordPeopleVersioned,MasterClient);
SlaveServer.RecordVersionSynchronizeSlave(
slave.db3
TSQLRecordPeopleVersioned,MasterClient);
MasterClient := TSQLHttpClientWebSockets.Create(
'127.0.0.1',HTTP_DEFAULTPORT,MasterModel);
MasterClient.WebSocketsUpgrade('PrivateAESEncryptionKey');
SlaveServer := TSQLRestServerDB.Create(SlaveModel,'slave.db3');
SlaveServer.RecordVersionSynchronizeSlaveStart(
TSQLRecordPeopleVersioned,MasterClient);
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
SynDB
DB.pas
ZDBC ODBC OleDB Oracle SQLite3
TDataset
FireDAC
NexusDB BDE DBExpress UniDAC
AnyDAC
external
internal
table
table
REST
TSQLRestServerDB.EngineAdd TSQLRestServerStaticExternal.EngineAdd
TSQLRequest ISQLDBStatement
By-passed if possible
direct
virtual
TObjectList External DB
DB.pas
direct
TDataSet
Oracle SQLite3 ODBC OleDB ZDBC FireDAC AnyDAC UniDAC BDE DBExpress NexusDB
ServerDB := TSQLRestServerDB.Create(Model,'application.db'),true);
ServerDB.CreateMissingTables;
Server := TSQLHttpServer.Create('8080',ServerDB);
Document is indexed:
by TSQLRecord.ID: integer
by Name: RawUTF8
Schema-less data
{ name : "Joe", x : 3.3, y : [1,2,3] }
{ name : "Kate", x : "abc" }
{ q : 456 }
MongoDB
SynMongoDB.pasfor direct access
mORMotMongoDB.pas for ODM integration
SynMongoDB.pas
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
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