Pull to refresh

Eloquera 4

Reading time8 min
Views1.9K

Краткое описание базы


База данных Eloquera с самого начала была написана для хранения объектов  на основе .Net Framework, что сделало возможным попытаться вобрать в себя все лучшее от объектных и реляционных баз данных одновременно, преодолев многие их различия. Теоретически Eloquera может работать с любыми языками из семейства .Net Framework, однако на практике работа проверялась пока только с C#. Главная ориентированность разработчиков на enterprise сегмент (100+ ГБ), а не на embedded решения, хотя последние тоже не обделены вниманием.

Отличительные особенности Eloquera весьма внушительны и постоянно пополняются, вот их очень краткий список:
  • Сохраняет C# объекты (любые объекты любого языка на .Net платформе) без необходимости реализации специальных интерфейсов и адаптеров.
  • Сохраняет Dynamic объекты с любыми полями\свойствами и может сопоставить их объектам любого типа.
  • Язык запросов максимально приближен к SQL, при этом не требуется наличие какой либо реляционной SQL базы. Плюс поддержка LINQ.
  • Возвращает объекты в том виде, в котором они были сохранены (включая перечислимые типы)
  • Поддержка параметров в виде списков и массивов
  • Регулярные выражения в запросах.
  • Поддержка шаблонных объектов.
  • Восстановление Read-only полей и свойств.
  • Поддерживается частичный возврат объектов. Например, если вам требуется класс ForumTopic, тогда можно не подтягивать все ссылки на ForumMessages.
  • Можно указать глубину объекта для возврата в запросе.
  • Хранимые процедуры.


Установка


Забрать дистрибутивы базы можно с официального сайта www.eloquera.com после регистрации. На выбор будут представлены архивы для desktop установки и для установки в виде сервиса (х86 или х64). При установке Eloquera как сервиса, подводных камней нет.

Установка на любой более-менее современной машине займет не более 5 минут. После чего в вашем распоряжении будут:
  • Eloquera Config Studio;
  • Eloquera DB Studio;
  • Сама служба, отвечающая за работу базы.

Desktop версия устанавливается по принципу x-copy, т.е. надо всего лишь скопировать файлы в нужную директорию. Для работы будет необходим установленный .Net 4 Full Framework.

При таком подходе вполне ожидаемым выглядит NuGet пакет, однако на данный момент такого пока что нет. Однако разработчики помнят о такой возможности и грозятся в скором времени создать таковой, как только для автономной версии базы ядро будет оформлено в виде библиотеки, а не исполняемого файла.
 

Режимы работы базы


БД Eloquera может работать в нескольких режимах:
  • Общая база данных для нескольких приложений, стандартный режим.
  • In-memory режим.
  • Desktop – режим встроенной в приложение базы.

Код для соединения с сервером и создания базы:
private const string DBName = "ServiceDatabase";

using (var eloquera = new DB("server=localhost:43962;options=none;")) {
        eloquera.CreateDatabase(DBName);
        eloquera.OpenDatabase(DBName);

        eloquera.Close();
    }

Для соединения с базой данных используется класс DB. Конструктору класса передается строка соединения, в данном примере соединение идет к сервису.

Eloquera поддерживает in-memory режим как при работе в виде сервиса, так и при автономной работе (desktop mode). В бесплатной версии, база в памяти может занимать до 1 ГБ. Так же стоит помнить о физической доступности оперативной памяти, так как возможна ситуация когда размер базы будет таков, что Windows попытается разместить ее в файле подкачки на диске. Как вы понимаете, это совсем не прибавит скорости при работе.

Для того чтобы указать движку, что мы хотим создать базу в оперативной памяти, надо будет указать специальный параметр inmemory в строке соединения.
new DB("server=(local); options=inmemory;"))

При этом база будет существовать только в оперативной памяти, однако пустой файл все равно будет создан в файловой системе. Для того чтобы можно было возобновить работу с такой базой, надо использовать параметр persist в строке соединения в опциях

Для работы в режиме desktop строка соединения будет такой:
new DB("server=(local); options=none;"))

Для того чтобы Eloquera стала работать в Desktop режиме, надо остановить сервис EloqueraDB, иначе вы получите ошибку о том, что невозможно соединится с сервисом по адресу (local).

Очень много всего интересного в базе, но остановлюсь на самом интересном наверно.
 

JOINs


Общий синтаксис операции:
SELECT Alias1,Alias2 FROM Type1 Alias1 [ LEFT | RIGHT| INNER | FULL ] JOIN Type2 Alias2 ONSomeFunction(Alias1.Field1, Alias2.Field2)

Если при построении запроса с использованием  JOIN в SELECT были использованы два разных типа  или больше, то результатом такой операции будет новый объект IEnumerable<Dictionary<string, object>>.

JOIN запросы, так же как и другие типы запросов, могут использовать именованные параметры. В том числе в выражении ON. Однако следует помнить о некоторых ограничениях:
  • Значение параметра должно быть определено до того как начнется выполнение запроса.
  • Именованные параметры не могут быть использованы для замены имен типов в выражении Select. Т.е. попытка  вызвать Select type будет вне правил.

Отдельно стоит упомянуть о том, как решается вопрос с наследниками классов, участвующих в построении выражения JOIN. Стандартным поведением считается возможность использования наследованных типов в запросе. Например, если TypeC  унаследован от  TypeA, тогда выражение:
SELECT a, b FROM TypeA a INNER JOIN TypeB b ON b.id = a.id

может вернуть объекты типа TypeC в поле «а», если они удовлетворяют условиям выражения. Для того чтобы избавиться от всех потомков класса в результатах запроса, следует использовать слово ONLY. Т.е. переписать запрос вот так:
SELECT a, b FROM ONLY TypeA a INNER JOIN TypeB b ON b.id = a.id

Теперь в поле «а» будут только объекты типа TypeA.

Пример в картинках на работу Inner Join. Пусть у нас есть такая структура данных:

Перед нами стоит задача найти все школы и рабочие места, находящиеся в одном месте.
Код:
var queryResult = (IEnumerable<Dictionary<string,object>>)

db.ExecuteQuery("SELECT sch, wp FROM School sch INNER JOIN WorkPlace wp ONch.Location=wp.Location");

Результаты в виде таблицы можно представить так:
#
queryResult[“sch”]
queryResult[“wp”]
1
School1
wPlace2
2
School2
wPlace2
3
School3
wPlace3
4
School3
wPlace4

Параметры


Параметры могут быть использованы только для передачи данных в запрос, так что фантазировать на тему получения данных через параметры бесполезно.

Использовать параметры очень просто:
Parameters param = db.CreateParameters();
param["name"] = "John"

Для использования параметра в запросе, надо использовать перегруженный метод, который их принимает. Например:
var res = db.ExecuteQuery("SELECT BasicUser WHERE Name = @name", param);

Массив значений параметра, может трактоваться базой как простой массив:
Parameters param = db.CreateParameters();
param.AddList("emails", new string[]{"john@gmail.com", "david@hotmail.com"});
var res = db.ExecuteQuery("SELECT BasicUser WHERE ALL @emails in Emails", param);

Параметры могут быть использованы с Top, Skip и Order By. Так же параметры могут содержать null.
 

Хранимые процедуры


Начиная с версии 4.0 Eloquera поддерживает хранимые процедуры.

Хранимые процедуры могут рассматриваться как методы расширения к основной базе. Они пишутся с использованием C#, за что благодарность создателям, за то, что они не выдумали какой-либо свой интерпретируемый диалект для этого дела. Получается, что можно использовать все возможность .Net при написании процедур.

Итак, хватит слов, лучше показать, как создаются хранимые процедуры на деле.

Первым делом надо объявить интерфейс  с желаемыми процедурами. Данный интерфейс должен находиться на стороне клиента и сервера.
public interface ICityStatisticSP{
    CityCars GetCityCars(string cityName);
}

Затем создаем класс, который нужен будет только на стороне сервера. При этом библиотеку с реализацией процедуры надо поместить в папку Lib в директории базы, либо настроить путь до библиотек с хранимыми процедурами с помощью параметра StoredProceduresPath.
public class CityStatisticSP: StoredProcedure, ICityStatisticSP {
     public CityCars GetCityCars(string cityName)  {
         Parameters parms = db.CreateParameters();
         parms["city"] = cityName;

         var cars = db.ExecuteQuery("SELECT Car FROM Car JOIN Seller ON Car.SellerID = Seller.ID WHERE Seller.City = @city", parms)
             .OfType<Car>()
             .ToList();
           …
     }
 }

Добавление новых процедур не требует перезапуска сервиса базы данных.

После того, как вы закинули библиотеку с процедурами к серверу, на клиенте можно будет вызвать процедуру с помощью следующего кода:
ICityStatisticSP procedures = db.GetStoredProcedureClass<ICityStatisticSP>();
string cityName = "Chicago";
CityCars cars = procedures.GetCityCars(cityName);

Исходя из самой объектной природы базы, не требуется настраивать для процедуры конфигурации маппинга и прочего-прочего-прочего.

Наличие хранимых процедур в существующем виде решает более сложные задачи, нежели простое сохранение и повторный вызов запросов к базе. Стоит акцентировать внимание на том, что весь код выполняется на стороне базы. Т.е. с помощью процедур можно очень сильно сократить нагрузку на сеть, когда с помощью процедур можно более эффективно фильтровать данные на стороне сервера, по результатам фильтрования, к примеру, создавать новые элементы и сохранять их в базе. Я думаю, что нетрудно себе представить ситуацию, когда надо каким-либо значением дописать множество элементов из базы. При старом подходе пришлось бы выгрузить все элементы, создать выборку по условиям для обновления, обновить, и перегнать новые данные по сети обратно. Хранимая процедура решит такие задачи гораздо эффективнее.
 

Динамические объекты (Dynamic)


По утверждению разработчиков Eloquera они добавили немного магии к объектной базе и получили уникальный функционал и объект, который назвали Dynamic. Вы уже догадались, откуда ноги растут у этой фичи, и с чем она идеологически согласована в C#. Динамические объекты могут хранить в себе как структурированные данные, т.е. классы и структуры определенные вами в C# коде, так и произвольно составленные. При этом можно свободно представлять эти объекты в виде друг друга.

Основным достоинством является возможность добавлять и удалять поля из сохраненного объекта – данные магическим образом присоединятся и встроятся в объект.
Преимущества, которые предоставляют динамические объекты:
  • Их легко создавать и использовать. Не надо беспокоиться о пропущенных полях и свойствах. Любое количество полей любого типа может быть добавлено в runtime.
  • Они автоматически определяют тип поля и работают с ним в соответствии с его возможностями и ограничениями. Динамические объекты в полной мере поддерживают индексацию.
  • Они могут ссылаться друг на друга и содержаться друг в друге.
  • Динамические объекты очень-очень быстрые.
  • Они  могут быть конвертированы на лету в «родные» объекты и обратно.
  • Для работы не требуется схема данных, что дает очень широкое поле для деятельности.
  • Движки для блогов, CMS, wiki
  • Профили и регистрация пользователей
  • Хранение истории записей
  • Случаи, когда данные надо фильтровать или агрегировать в runtime.
  • Приложения, оперирующие с переменных числом атрибутов разных типов.

По поводу последних двух пунктов надо пояснить, что имеются в виду различные программы, которые позволяют пользователям самостоятельно конструировать типы данных, динамически составляют интерфейс для каждого пользователя. Хранить такие данные в строгом виде нет никакой рациональной возможности без взрывной сложности. Использование Dynamic позволяет описывать такие типы в бесконечном многообразии и работать с ними в едином стиле.

Еще примером может служить веб 2.0, когда пользователи могут добавлять свои комментарии ко всему, ассоциировать материалы и так далее. С традиционными реляционными базами данных, жестким описанием классов, такие схемы невозможно или очень сложно будет реализовать.
 

Быстрый обзор работы с dynamic объектами


Структура динамических объектов может быть модифицирована  в любой момент вместе с содержащимися данными. Вместе с простотой использования, это дает более чем широкие возможности для эволюции данных.
Dynamic @do = new Dynamic();
 
@do["Title"] = "Some title";
@do["Price"] = 14.99;
@do["DateAdded"] = DateTime.Now;
 
db.Store(@do);
 
Dynamic res = (from Dynamic d in db where d["Price"] == 14.99 select d).First<Dynamic>();

То же самое возможно и с использованием переменных типа dynamic представленных в .Net 4.
dynamic @do = new Dynamic();
@do.Title = "Some title";
@do.Price = 14.99;
@do.DateAdded = DateTime.Now;
 
db.Store(@do);
 
dynamic res = (from Dynamic d in db where d["Price"] == 14.99 select d).First<Dynamic>();


Прошу заметить, что при использовании LINQ необходимо использовать d[“Price”]  для явного указания на постройку дерева выражений.

При работе с динамическими объектами есть возможность узнать все поля, которые содержит объект:

Dynamic @do = dynamics[0];
 
foreach (var field in @do) {
   Console.WriteLine(String.Format("Field Name {0} Value {1} Type {2}", field.Key, field.Value, field.Type));
}


Помимо широких возможностей есть и некоторые ограничения, в частности есть список символов, которые нельзя употреблять при задании имен полей. Это направлено на то, чтобы избежать коллизий во время написания SQL запросов к объектам. Вот список зарезервированных символов:

., % ] [ + — $! * ( )

Надеюсь, что вы заинтересуетесь базой и как минимум возьмете базу на заметку для домашних экспериментов.

Могу организовать цикл статей если будет интересно, материал готовый есть.

 
Tags:
Hubs:
+19
Comments17

Articles