Как стать автором
Обновить

AcroDb. Новый провайдер данных

Время на прочтение4 мин
Количество просмотров957
Автор оригинала: Oleksiy Glib
Рождение новой CMS-системы часто начинается с проектирования архитектуры и реализации самых простых блоков этой архитектуры.
Сегодня, я начинаю цикл статей, посвящённых новой системе управления сайтом реализованной на языке C# и платформе .Net. Система планируется быть с открытым исходным кодом, и данными статьями, я постараюсь описать все её элементы в порядке их начального появления и проектирования ещё года 2 назад.
Началом был универсальный слой доступа к любому провайдеру данных (то ли реляционная БД, или не реляционная, или даже своя организация базы данных).
Кого заинтересовал, прошу под кат.

Как и всё, что мы хотим сделать гениальным и простым, должно быть ещё и удобным, быстрым, и гибким. Так хотелось сделать и со слоем доступа к данным. Прошу заметить, любым данным :)
Самый простой метод для программиста был всегда использование какой-либо ORM системы. В .Net Framework этого добра хватает, начиная с истоков — NHibernate, Nolics, LINQ2SQL, Entity Framework, и куча самописных… Какие шаги обычно должен сделать разработчик, чтобы подключить какую-либо ORM систему к проекту?
  • Выбор бд (обязательно реляционной)
  • Выбор ORM-системы для работы с бд
  • Создание таблиц и связей в бд
  • Создание прототипов таблиц в виде классов в коде (у LINQ2SQL этот шаг можно автоматизировать утилитой sqlmetal, а EF вообще сам делает это)
  • Для таких систем как Nolics.net нужен ещё шаг описания интерфейса для прототипа таблицы и описание структуры таблицы в его собственном языке, но отпадает нужда создавать таблицу в бд ручками. Nolics при старте сделает автоматическую миграцию, если его об этом хорошо попросить :)
  • Дальше разработчик пишет классы управления данными, как добавление, редактирование, удаление, выборка

И всё вроде как круто. Но! Приходит время, когда заказчику не нравится субд (может она дорогая или медленная а тут появляется MongoDB которая у всех на устах). И программисту приходится переписывать и переделывать весь слой доступа к данным. Опять почти всё те же шаги (прошу не пинать меня любителей гибкой архитектуры, в которой всё уже давно предусмотрено, мы не о тех задачах пока говорим:) ).
Вот и родилась мысль унифицировать доступ к разным провайдерам предоставляя интерфейс CRUD операций и не предоставляя отношений между таблицами (не все провайдеры бд знают об отношениях, а как проделать отношения в AcroDB я расскажу в следующих статьях). Чего я хотел добиться?
  • Создать гибкий движок-замену слою доступа к данным для среднего размера проектов и малых тоже
  • Создать метод описания таблицы только один раз и в одном месте
  • Чтобы использование ORM было скрыто от разработчика, и запросы проводились только выражениями LINQ
  • Чтобы при отстутствии описания таблицы в провайдере данных (субд) автоматически при запуске создавалась данная таблица, без участия разработчика

Что из этого получилось? Проект AcroDB вы можете скачать с сайта github'а
Давайте посмотрим, что вам нужно для использования любой таблицы с её автоматическим созданием (подробный пример есть в подпроекте AcroDbTest в сорцах).
Первое, вам нужно описать интерфейс будующей таблицы:
  [AcroDbEntity]
  public interface IUser
  {
    Guid ID { get; set; }
    string Name { get; set; }
  }


* This source code was highlighted with Source Code Highlighter.

помечая его аттрибутом AcroDbEntity вы указываете системе что на основе этого интерфейча нужно создать в памяти класс который его имплементирует и использовать этот класс для работы с внутренней ORM-системой. неплохо? :) идём дальше.
Далее нам нужно при запуске проекта настроить подключение к нужному провайдеру данных (пока поддерживается MsSql и MongoDB для тестирования):
    static string[] SettingsCallBack(string name)
    {
      if (name == "MsSql")
        return new[] { @"server=OLEKSIY-PC\SQLEXPRESS;Database=acrodbtest;Trusted_Connection=True;" };
      return new string[0];
    }
    static void Main()
    {
      DataContextFactory.SettingsCallback = SettingsCallBack;
      DataContextFactory.Instance.ScanAssembly(typeof(MsSqlDataContext).Assembly);
      //...
    }


* This source code was highlighted with Source Code Highlighter.

Метод SettingsCallBack используется для подстановки конфигурационных данных для настройки провайдера данных. в нашем примере это строка подключения к СУБД.
Класс DataContextFactory это синглтон, который предоставляет по запросу контексты разных провайдеров данных. Для того чтобы DataContextFactory знал о новых провайдерах данных, его методу ScanAssembly нужно скормить сборку, где возможно есть информация о таком провайдере, и рефлексивно он выполнит поиск.
Теперь нам нужно настроить генератор контекстов доступа к данным на использование провайдера:
  AcroDataContext.DefaultDataContext = DataContextFactory.Instance.Get("MsSql");
  AcroDataContext.ScanAssemblyForEntities(Assembly.GetExecutingAssembly());


* This source code was highlighted with Source Code Highlighter.

AcroDataContext тоже синглтон, а метод ScanAssemblyForEntities ищет интерфейсы помеченные аттрибутом AcroDbEntity в сборке и создаёт классы-прототипы, для использования в ORM.
Как дальше пользоваться CRUD операциями:
  using (var manager = AcroDataContext.Go)
  {
    var usr = manager.Provide<IUser>().Create();
    usr.Name = "Some user name";
    manager.Provide<IUser>().Save(usr);
    manager.SubmitChanges();
  }


* This source code was highlighted with Source Code Highlighter.

Опишу тут только одну строку — AcroDataContext.Go. Это создание контекста подключения к провайдеру данных уже подключённого и готового к работе. Не забывайте его закрывать методом Dispose.
Для того, чтобы на основе описания вашего интерфейса в провайдере данных было создано описание таблицы (в данном случае в субд будет создана таблица Users с первичным ключём ID и полем Name с типом nvarchar(255)), нужно после сканирования сборок на интерфейсы вызвать метод «AcroDataContext.PerformMigrations()». Миграции делаются на основе SubSonic Migrations. Раньше они делались с помощью SQL SMO.

На этом не заканчивается функциональность данной библиотеки, но я с радостью опишу дополнительные элементы, если кому-то это будет нужно. А также, нетерпеливые могут прочитать исходный код :)
За первую статью прошу сильно не пинать, постараюсь ответить на все вопросы :)
Теги:
Хабы:
Всего голосов 13: ↑6 и ↓7-1
Комментарии10

Публикации

Истории

Работа

.NET разработчик
60 вакансий

Ближайшие события

27 августа – 7 октября
Премия digital-кейсов «Проксима»
МоскваОнлайн
11 сентября
Митап по BigData от Честного ЗНАКа
Санкт-ПетербургОнлайн
14 сентября
Конференция Practical ML Conf
МоскваОнлайн
19 сентября
CDI Conf 2024
Москва
24 сентября
Конференция Fin.Bot 2024
МоскваОнлайн
25 сентября
Конференция Yandex Scale 2024
МоскваОнлайн
28 – 29 сентября
Конференция E-CODE
МоскваОнлайн
28 сентября – 5 октября
О! Хакатон
Онлайн
30 сентября – 1 октября
Конференция фронтенд-разработчиков FrontendConf 2024
МоскваОнлайн