mORMot — это набор библиотек для разработки программного обеспечения на основе сервис-ориентированной архитектуры (распределенных, слабо связанных заменяемых компонентов, со стандартизированными интерфейсами и протоколами, в данном случае на основе REST). Все библиотеки доступны в виде исходного кода и распространяются по лицензии MPL, GPL или LGPL (на выбор).
Набор библиотек содержит большое количество полезных компонентов: сетевого взаимодействия, доступа к БД, шифрования, сжатия данных, создания PDF, выполнения JavaScript, ORM и многое другое. Все компоненты минимально связаны друг с другом — можно использовать только те, которые нужны. Например, для создания PDF нужно добавить в свой проект всего три файла:
SynPDF.pas
, SynCommons.pas
и SynLZ.pas
.
Разработка ведется в основном одним человеком — Арно Буше (Arnaud Bouchez). Желающие помогают ему с кодом разных компонентов. Например, код выполнения JavaScript с помощью движка Spider Monkey написал Павел Машляковский. Я написал код прозрачной аутентификации пользователя в домене Active Directory. Все-таки, открытый исходный код и совместная разработка — это здорово!
В одном из своих приложений я использовал практически весь набор библиотек. С приложением активно работают несколько десятков пользователей, в базе данных SQLite около 20 Гб данных. За время разработки и эксплуатации приложения библиотека на деле подтвердила свое качество и стабильность. Ошибки конечно бывают, но оперативно исправляются.
Именно быстрая (буквально в течение пары дней) и адекватная реакция автора на баги и недоработки является серьезным преимуществом библиотеки. А если что-то не получается, всегда можно спросить совета на форуме. Сравните с тем, как я пытался решить проблему с багом в компиляторе Delphi XE2. В результате, всего через год ошибку починили, в версии XE4, которую нужно купить, чтобы компилятор заработал правильно.
Библиотека имеет хорошую документацию, основной документ «Software Architecture Design» содержит 1500 страниц (в формате PDF). Читать их все на первых порах необязательно, но очень желательно.
Пример использования
Приведу краткий пример для быстрого знакомства с mORMot.
Первым делом следует определить модель данных, с которой будет работать наше приложение. Для этого мы объявляем классы-наследники
TSQLRecord
.
Модель данных мы поместим в отдельный модуль SampleData.pas, общий для клиента и сервера. В нашей модели будет один класс — TSQLSampleRecord
. Поля класса из секции published
будут участвовать в сериализации, то есть передаваться между клиентом и сервером, сохраняться в базе данных, использоваться ObjectToJSON
/JSONToObject
и в других местах.
TSQLSampleRecord = class(TSQLRecord) private FQuestion: String; FName: String; FTime: TModTime; published property Time: TModTime read FTime write FTime; property Name: String read FName write FName; property Question: String read fQuestion write FQuestion; end;У каждого наследника
TSQLRecord
есть поле ID
, это первичный ключ в базе данных.
Для нашего класса
TSQLSampleRecord
в базе данных будет создана таблица SampleRecord
(при вызове TSQLRestServer.CreateMissingTables
):
CREATE TABLE SampleRecord ( ID INTEGER NOT NULL PRIMARY KEY, Time INTEGER, Name TEXT, Question TEXT );Разные классы-наследники
TSQLRecord
могут сохраняться в разных базах данных.
Далее мы создаем модель — экземпляр
TSQLModel
, в которой будут собраны вместе наследники TSQLRecord
.
В модели нужно указывать только классы, сохраняемые в базе данных. Каждый наследник TSQLRecord
, добавленный в модель TSQLModel
, будет представлен таблицей в базе данных, и сервер будет предоставлять удаленный доступ к нему.
function CreateSampleModel: TSQLModel; begin Result := TSQLModel.Create([TSQLSampleRecord]); end;Создаем экземпляр сервера. Сервер будет сохранять и получать классы-наследники
TSQLRecord
в базе данных.
FDatabase := TSQLRestServerDB.Create(FModel, ChangeFileExt(ParamStr(0), '.db3')); FDatabase.CreateMissingTables();Теперь мы можем сохранять в базе данных экземпляры
TSQLSampleRecord
:
var LSampleRecord: TSQLSampleRecord; begin LSampleRecord:= TSQLSampleRecord.Create(); try LSampleRecord.Name := NameEdit.Text; LSampleRecord.Question := QuestionMemo.Text; if Database.Add(LSampleRecord, True) = 0 then raise Exception.Create('Error adding the data'); finally LSampleRecord.Free(); end; end;И получать экземпляры
TSQLSampleRecord
из базы данных:
var LSampleRecord: TSQLSampleRecord; begin LSampleRecord := TSQLSampleRecord.Create(Database, 'Name=?', [NameEdit.Text]); try if LSampleRecord.ID = 0 then QuestionMemo.Text := 'Not found' else QuestionMemo.Text := LSampleRecord.Question; finally LSampleRecord.Free(); end; end;Немного изменив код, мы можем перейти к клиент-серверной архитектуре на основе REST. Модель данных будет общая для клиента и для сервера. На сервер мы добавим создание экземпляра
TSQLHttpServer
, а на клиенте вместо TSQLRestServerDB
будем использовать TSQLHttpClient
.
Организовываем доступ к серверу по протоколу HTTP:
FServer := TSQLHttpServer.Create('80', [FDatabase], '+', HTTP_DEFAULT_MODE);Подключение клиента к серверу:
FDatabase := TSQLHttpClient.Create('localhost', '80', FModel); FDatabase.SetUser('User', 'synopse');Здесь описана только очень небольшая часть возможностей mORMot, только чтобы заинтересовать читателя. Подробней лучше почитать в документации, посмотреть примеры.
Полный код примеров, части из которых были показаны выше:
01 - In Memory ORM,
02 - Embedded SQLite3 ORM,
04 - HTTP Client-Server.
Быстрая сборка примеров:
- Скачайте архив текущей версии исходного кода с GitHub — файл mORMot-master.zip. Распакуйте архив в любое удобное место.
- Скачайте файл sqlite3obj.7z и распакуйте его в папку
mORMot-master
, получившуюся на предыдущем шаге. - Откройте нужный файл проекта в Delphi (например,
mORMot-master\SQLite3\Samples\02 - Embedded SQLite3 ORM\Project02.dpr
) и в свойствах проекта добавьте вSearch path
пути..\..\;..\..\..\
, должно получиться, как на рисунке ниже. - Для запуска примеров «13 - StandAlone JSON SQL server» и «17 - TClientDataset use» нужна база данных
test.db3
. Она создается при запуске тестов, файл проектаmORMot-master\SQLite3\TestSQL3.dpr
.
В следующей статье я планирую описать код аутентификации пользователя в домене Active Directory, написанный мной для mORMot.
Для изучения примеров нужна база test.db3.
ОтветитьУдалитьПомогите плиз её найти.
БД должна создаться автоматически при первом запуске сервера.
УдалитьПокажите тогда код, где она создаётся... Я не нашел!
УдалитьСейчас понял, о чем вы.
УдалитьБаза test.db3 создается при запуске тестов, проект
mORMot-master\SQLite3\TestSQL3.dpr.
Пасиб...
УдалитьХорошая статья, давно интересно было прочитать, но времени мало очень, пиши ещё, спасибо
ОтветитьУдалитьКлассная библиотека. Нагрузил парой тысяч корпоративных клиентов http/rest. Работает как часы.
ОтветитьУдалитьДа, библиотека хорошая, но вопросов тьма...
ОтветитьУдалитьГотов финансировать небольшой проект на mORMot, может кому интересно будет...откликнитесь.
Мил человек, подскажи, как сделать каскадное удаление? Уже всю голову сломал, документацию перерыл, но не хочет TRecordReferenceToBeDeleted нормально отрабатываться.
ОтветитьУдалитьЗадача - есть дерево, составленное из всяких TSQLRecord, нужно, чтобы при удалении узла убивались все потомки.
Так, разобрался с TRecordReferenceToBeDeleted, и нашёл ТАКИЕ грабли..
Удалитьfunction TSQLRecord.RecordReference(Model: TSQLModel): TRecordReference;
begin
if (self=nil) or (fID<=0) then
result := 0 else begin
result := Model.GetTableIndexExisting(PSQLRecordClass(Self)^);
if result>63 then // TRecordReference handle up to 64=1 shl 6 tables
result := 0 else
inc(result,fID shl 6);
end;
end;
Вот так, по-простому, в первых 6 битах хранит номер!!! таблицы в модели, а в остальных - ID. И что получается ? А ничего хорошего:
1) Количество таблиц для всяких связок не должно превышать 63.
2) Если, не дай бог, поменяли модель, то кирдык всем связкам. Удобно, что говорить
И как выворачиваться, непонятно :(
1. 63-х таблиц обычно достаточно.
Удалить2. Да, в данном случае нельзя менять порядок таблиц в модели, т.е. можно только добавлять новые.
Вообще, в mORMot можно делать быстро и просто, а можно сложнее и гибче.
Я обычно использую Client-Server services via interfaces. Там можно реализовать логику любой сложности. И взаимодействие клиента и сервера более наглядно.
Но ведь в случае интерфейсов есть проблема - каскадное удаление, ссылочная целостность и создание таблиц нужно делать ручками на сервере?
УдалитьКстати, я извратился построить дерево по 200+ таблиц с каскадным удалением на чистом mORMot-е. Если нужно, обращайтесь.