Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

StubDb — база данных на стабах для стремительного прототипирования и не только

Anna | 17.06.2014 | нет комментариев

О чем это

Добросердечного времени суток!

Я бы хотел рассказать о StubDb — библиотеке для стремительного прототипирования приложений и легкого юнит тестирования. Она разрешает заменять работу с реальной базой данных, на работу с данными хранимыми в памяти/файле. Это дает вероятность сконцентрироваться на классах доменной модели, а не на особенностях хранения данных. StubDb использует правило работы Entity Framework Code First, что делает комфортным их совместное применение, но может применяться отдельно.

Дабы написать Data Persistence Layer, необходимо затратить много усилий. Работа с базой данных это — хлопотно: начиная от подключения и редактирования конфигов, и заканчивая написанием запросов. Прежде, пока ORM еще не были так знамениты, много времени занимало написание однообразных SQL запросов. С становлением ORM, поменьше времени расходуется непринужденно на SQL, но взамен этого нужно постигать особенности самих ORM фреймворков.

В теории все легко: программист работает с доменными объектами, метаморфозы в них транслируются в базу данных легко и безболезненно. Но на практике особенности фреймворков Зачастую вызывают недоумение и прострацию. Скажем, на данный момент на StackOverflow по ASP.NET MVC 77,852 вопросов, а по Entity Framework 33,276, поменьше, но не гораздо. А чай в идеале EF должен легко неприметно делать свою работу.

Безусловно, без БД не обойтись. Но когда приложение либо новая фича находятся в исходной стадии проектирования и разработки, в БД нет необходимости. На этом этапе абсолютно довольно: иметь доменную модель классов, беречь данные в этой модели совместно с взаимосвязями между отдельными классами (один к одному, многие ко многим), получать данные доменной модели, рассматривая эти связи. StubDb реализует данный наименьший комплект требований. Применяя StubDb на исходном этапе разработки, дозволено избежать трудностей работы с БД и ORM, но при этом иметь вероятность беречь данные в доменной модели и легко ее менять, не нарушая работоспособности приложения.

Для чего это нужно

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

Юнит тестирование
Иным отличным вариантом применения могут быть юнит тесты: запускать юнит тесты для бизнес логики дозволено на стабах, исключив работу с базой данных из тестирования. Работу с БД, дозволено протестировать отдельно в интеграционных тестах.

Стаб режим для приложения — разверни приложение в 3 клика
Мне пришлось поработать достаточно много на планах энтерпрайс яруса и, к сожалению, в моей практике это значило — огромная куча нехорошо и многообразно написанного кода, которая работает в продакшене и на которой зарабатывают настоящие деньги. При этом, Дабы пофиксить всякий баг, даже в пользовательском интерфейсе, необходимо потратить уйму времени на разворачивание плана на машине разработчика. Хотелось бы, Дабы в совершенном мире для плана дозволено было получить исходники из репозитория, поменять режим работы на режим разработчика в конфиге и план сразу бы запустился.
Со StubDb это может быть действительностью, если реализовать Stub DAL наравне с реальным DAL, и, вследствие этому, иметь вероятность трудиться с планом без доступа к реальной базе данных, веб-сервисам и прочим источникам данных, используемых на плане. Применяя Dependency Injection, и имплементируя интерфейсы классов доступа к данным (репозиториев), для реальных данных и для стабов, дозволено легко переключаться с реальных источников данных на стабы. Зачастую доступ к реальным данным не непременен, а изредка бывает затруднен (нет интернет соединения, задачи на сервере), в это время дозволено переключиться на стабы. Я теснее начал применять StubDb в таком режиме на нескольких планах. Время покажет насколько это применимо на практике.

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

Как этим пользоваться

Отменнее каждого показать на примере. Возьмем как пример примитивную доменную модель (ДМ):

public class Student 
{ 
       public int Id { get; set; } 
       public string FirstName { get; set; } 
       public string LastName { get; set; } 
       public virtual List<Enrollment> Enrollments { get; set; } 
} 

public class Course 
{ 
       public int Id { get; set; } 
       public string Title { get; set; } 
       public int Credits { get; set; } 
       public virtual Department Department { get; set; } 
       public virtual List<Enrollment> Enrollments { get; set; } 
} 

public class Department 
{ 
       public int Id { get; set; } 
       public string Name { get; set; } 
       public decimal Budget { get; set; } 
       public virtual List<Course> Courses { get; set; } 
} 

public class Enrollment  
{ 
       public int Id { get; set; } 
       public Grade Grade { get; set; } 
       public Student Student { get; set; } 
       public Course Course { get; set; } 
} 

public enum Grade 
{ 
       NoGrade, A, B, C, D, F 
} 

В этой доменной модели есть студенты и курсы, у всякого курса есть соответствующий отдел (кафедра), студент может быть записан на несколько курсов через Enrollment, если студент окончил курс, то в Enrollment будет храниться оценка по этому курсу.

Для того Дабы трудиться с приведенным примером ДМ, сотворим класс контекста. По аналогии с Entity Framework, необходимо наследоваться от базового StubContext.

Для всякой сущности, к которой мы будет строить отдельные запросы, создаем качество типа StubSet, вновь же, по аналогии с EF.

Должно получиться так:

public class SampleStubContext: StubContext 
{ 
       public StubSet<Course> Courses { get; set; } 
       public StubSet<Department> Departments { get; set; } 
       public StubSet<Enrollment> Enrollments { get; set; } 
       public StubSet<Student> Students { get; set; } 
} 

Это все минимальные настройки, нужные для работы.

Сейчас добавим в контекст данные:

    var context = new SampleStubContext();

    var departmentIt = new Department() {Budget = 40000, Name = "IT"};
    var departmentMath = new Department() {Budget = 14000, Name = "Math"};

    context.Departments.Add(departmentIt);
    context.Departments.Add(departmentMath); 
    //now departmentMath.Id == 2 like with EF it is updated after adding to context

    var courseJavascript = new Course() {Department = departmentIt, Title = "JavaScript basics"};
    var courseAlgorithms = new Course() {Department = departmentIt, Title = "Algorithms"};
    var courseAlgebra = new Course() {Department = departmentMath, Title = "Algebra"};

    context.Courses.Add(courseAlgebra);
    context.Courses.Add(courseAlgorithms);
    context.Courses.Add(courseJavascript);

    var studentAlex = new Student() {FirstName = "Alex", LastName = "Black"};
    var studentPer = new Student() {FirstName = "Per", LastName = "Sundin"};

    context.Students.Add(studentAlex);
    context.Students.Add(studentPer);

    context.Enrollments.Add(new Enrollment(){Student = studentAlex, Course = courseAlgebra, Grade = Grade.B});
    context.Enrollments.Add(new Enrollment(){Student = studentAlex, Course = courseAlgorithms, Grade = Grade.A});

    context.Enrollments.Add(new Enrollment() { Student = studentPer, Course = courseAlgorithms, Grade = Grade.C });
    context.Enrollments.Add(new Enrollment() { Student = studentPer, Course = courseJavascript, Grade = Grade.A });

У нас есть 2 кафедры Math и IT, в Math курс Algebra, в IT JavaScript и Algorithms. Есть два студента Alex и Per, Alex записан на курсы Algebra и Algorithms, Per — Algorithms и JavaScript

Напишем пару запросов к данным в контексте:

    var departmentItFromContext = context.Departments.Query().Single(x => x.Name == "IT");
    var coursesForIt = departmentItFromContext.Courses; //coursesForIt == { Javascript, Algorithms };

    var courseAlgorithmsFromContext = context.Courses.Query(2).First(x => x.Title == "Algorithms");
    var studentsForAlgorithms = courseAlgorithmsFromContext.Enrollments.Select(x => x.Student).ToList(); 
    // studentsForAlgorithms == {Alex, Per}

Запрашивая данные из доменной модели через контекст, мы получаем их с учетом взаимосвязей между объектами. Курсы для IT кафедры — Javascript, Algorithms; студенты записанные на Algorithms — Alex и Per.

Изменим данные в контексте:

    var alexAlgorithmsEnrollment = context.Enrollments.Query()
        .FirstOrDefault(x => x.Student.FirstName == "Alex" && x.Course.Title == "Algorithms");
    context.Enrollments.Remove(alexAlgorithmsEnrollment);

    var courseAlgorithmsFromContextUpdated = context.Courses.Query(2).First(x => x.Title.Contains("Algorithms"));
    var studentsForAlgorithmsUpdated = courseAlgorithmsFromContextUpdated.Enrollments.Select(x => x.Student); 
    //studentsForAlgorithms == {Per}

    courseAlgorithms.Department = departmentMath;
    courseAlgorithms.Title = "Methods of optimisation";
    context.Courses.Update(courseAlgorithms);

    var departmentMathFromContext = context.Departments.Query().Single(x => x.Name == "Math");
    var coursesForMath = departmentMathFromContext.Courses; 
    //coursesForMath == { Algebra, Methods of optimisation };

Мы удалили Enrollment для Алекса на Algorithms, позже этого в списке студентов подписанных на Algorithms Алекса теснее нет. Мы поменяли кафедру для Algorithms, позже этого данный курс возник в списке курсов его новой кафедры.

Примеры применения

План на GitHub: github.com/yegor-sytnyk/StubDb

Для комфорта применения сделан StubDb NuGet package.

Текст консольного приложения с доменной моделью из этой статьи здесь: gist.github.com/yegor-sytnyk/c3f9ba12f5bb6b188286.

MyUniversity: github.com/yegor-sytnyk/MyUniversity. Всецело работающий план на основе доменной модели из ContosoUniversity ASP.NET MVC tutorial. Реализован c DAL на StubDb, на примере этого плана видно как дозволено применять StubDb коллективно с Entity Framework.

Буду рад примечаниям и предложениям. Верю, это может быть пригодно еще кому-нибудь.

Как это работает

Для тех, кому увлекательны детали реализации.

Данные из ДМ хранятся в сущностях (Entities) и связях (Connections).

Сущности — это классы из ДМ (Student, Course, т.д.). Для всякого типа сущности, хранится словарь со всеми нынешними значениями этой сущности и ключом айди сущности. Как и в энтити фреймворке, ключ сущности может именоваться либо Id либо {ИмяКласса}Id, скажем StudentId, для сущности Student. Дабы излишне не усложнять реализацию, Id должно иметь тип Int.

Не зависимо от типа связи (один к одному, многие ко многим либо один ко многим), всякий элемент коллекции связей хранит данные о связях между двумя типами сущностей. Скажем, если у студента есть список курсов на которые он подписан, то в соответствующей связи для студента и курса будут храниться парные связи {студент(Id)-курс(Id)}. Таким образом, дозволено смоделировать все типы связей: один к одному, один ко многим, многие ко многим. Для случая один к одному будет хранится исключительный элемент связи, для случая множественного типа связи будет хранится несколько связей.

Применяя сущности и связи, дозволено записывать, читать данные из контекста ДМ, рассматривая связи между объектами.
Во время добавления данных, применяя Add/Update способы у StubSet, обновляются внутренние entities/connections в контексте. При вычитывании данных через способ Query, в сущностях инициализируются навигационные свойства, исходя из существующих связей. Если, скажем, у курса есть качество типа отдел, то в способе Query будет поиск по связям — есть ли связь которая объединяет курс с этим айди с каким-то из отделов. Если такая связь есть, то будет выставлен соответствующий отдел, напротив качество отдел будет выставлено в null. По тому же тезису инициализируются навигационные свойства с коллекцией объектов, скажем, лист зачислений на курсы для студента.

Есть еще ряд особенностей, но об этом отменнее прочитать в документации либо посмотреть начальный код на страничке плана.

 

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB