[Из песочницы] Разработка баз данных с Code First

imageПовсеместно принято, что в «серьезных» CRUD приложениях база данных становится во главу угла. Ее проектируют самой первой, она обрастает хранимыми процедурами (stored procedures), с ней приходиться возиться больше всего. Но это не единственный путь! Для Entity Framework есть Code First подход, где главным становится код, а не база. Преимущества:

Никакого генерированного кода База — это снова просто хранилище. Над ней не надо дрожать, дропается легко и без проблем. Простейшая установка среды разработки. Выкачал код и запустил — никакой возни с бэкапами. Есть и пара недостатков, но они скорее связаны с Entity Framework, а не с Code First подходом как таковым; о них чуть позже.

Ниже я покажу на примере, насколько просто разрабатывать с Code First подходом.

ПримерВозьмем простую модель: image

В качестве фронт-энда будет ASP.NET MVC, так что создаем соответствующий проект. Выбираем No Authentication — в этом проекте нельзя будет логиниться и весь контент доступен для всех.

Я сделал еще 2 проекта — для бизнес-объектов и DAL, но при желании можно просто создать соответствующие папки в web проекте. Не забудте установить Entity Framework в соответствующие проекты через NuGet.

image

Создаем классы, которые будут отображать сущности (entities):

public abstract class BaseEntity { [DatabaseGenerated (DatabaseGeneratedOption.Identity)] public Guid ID { get; set; } } public class Course: BaseEntity { public string Title { get; set; }

public int Credits { get; set; }

public ICollection Enrollments { get; set; } } public class Student: BaseEntity { public string Name { get; set; }

public int Age { get; set; }

public DateTime EnrollmentDate { get; set; }

public virtual ICollection Enrollments { get; set; } } public class Enrollment: BaseEntity { public Guid CourseID { get; set; }

public Guid StudentID { get; set; }

public Grade CourseGrade { get; set; }

public virtual Student Student { get; set; }

public virtual Course Course { get; set; } } Как видно, все повторяющееся свойства (properties) можно убрать в абстрактный класс и наследоваться от него. В данном случае у каждой таблицы будет Primary Key колонка типа Guid, который будет генерироваться при записи в базу.

Grade — это просто энумератор, ничего особенного:

public enum Grade { A, B, C, D, E, F } Создаем контекстный класс:

public class UniversityContext: DbContext { public UniversityContext () : base («UniversityContext») { }

public DbSet Courses { get; set; } public DbSet Enrollments { get; set; } public DbSet Students { get; set; }

protected override void OnModelCreating (DbModelBuilder modelBuilder) { base.OnModelCreating (modelBuilder);

modelBuilder.Entity() .HasMany (s => s.Enrollments) .WithRequired (e => e.Student) .HasForeignKey (e => e.StudentID);

modelBuilder.Entity() .HasMany (c => c.Enrollments) .WithRequired (e => e.Course) .HasForeignKey (e => e.CourseID);

} } Отношения дефинированы через Fluent API, читаются с конца — например, Student — Enrollment относятся как one (Student): many (Enrollment).

Стоит отметить, что конфигурировать модели можно как через Fluent API, так и аннотациями. Для некоторых настроек аннотаций не существует, но их можно создать самим. Я предпочитаю все-же Fluent API.

И, наконец, заполнение базы данными:

public class UniversityInitializer: System.Data.Entity.DropCreateDatabaseIfModelChanges { protected override void Seed (UniversityContext context) { var studentList = new List() { new Student (){ Age = 20, EnrollmentDate = DateTime.Now, Name = «Basil Ivanov» }, new Student (){ Age = 18, EnrollmentDate = DateTime.Now, Name = «Boris Ivan» }, new Student (){ Age = 27, EnrollmentDate = DateTime.Now, Name = «Masha Ivanova» }, new Student (){ Age = 23, EnrollmentDate = DateTime.Now, Name = «Vytautas» }, new Student (){ Age = 21, EnrollmentDate = DateTime.Now, Name = «Ivan» } }; studentList.ForEach (s => context.Students.Add (s)); context.SaveChanges ();

var courseList = new List() { new Course (){ Credits = 10, Title = «Maths»}, new Course (){ Credits = 20, Title = «Advanced maths»}, new Course (){ Credits = 10, Title = «Physics»} }; courseList.ForEach (c => context.Courses.Add©); context.SaveChanges ();

var enrollments = new List() { new Enrollment (){ Course = context.Courses.FirstOrDefault (c => c.Title==«Maths»), Student = context.Students.FirstOrDefault ()}, new Enrollment (){ Course = context.Courses.FirstOrDefault (c => c.Title==«Physics»), Student = context.Students.FirstOrDefault ()}, new Enrollment (){ Course = context.Courses.FirstOrDefault (c => c.Title==«Physics»), Student = context.Students.FirstOrDefault (s => s.Name == «Boris Ivan»)} }; enrollments.ForEach (e => context.Enrollments.Add (e)); context.SaveChanges ();

} } Последнее, что надо сделать — добавить информацию в web.config. Используем LocalDb, которая идет вместе с Visual Studio, которой вполне достаточно для целей этого проекта. Следующий код идет в элемент configuration:

А следующая разметка — в элемент entityFramework:

В атрибуте type элемента context указываются через запятую название класса контекста и assembly, где этот класс находится. То же самое для инициализатора в элементе databaseInitializer.

Это вообщем-то и все, проект готов к запуску.

В Visual Studio 2013 можно по-быстрому сгенерировать Controller и View к выбранной модели через диалог Add → New Scaffolded Item.

image

Скачать пример можно тут.

Недостатки Во-первых, к существующей базе данных подобный подход применить сложно. Так что вообщем-то это для разработки с нуля.Часто подножки ставит Entity Framework, который часто принимает решения за программиста — есть так называемые конвенции, что, допустим, property который называется Id, будет по умолчанию преобразован в Primary Key таблицы. Мне такой подход не нравится.Продолжение темы Разработка с помощью Code First подхода в Entity Framework достаточно объемная тема. Я не касался вопроса миграций, проблем с многопоточностью (concurrency) и многого другого. Если сообществу интересно, я могу продолжить эту тему в дальнейших статьях.Материалы:

1. Getting started with Entity Framework 6 Code First using MVC 5

2. Database initialization in Code-First

3. Lerman J., Miller R. — Programming Entity Framework. Code First (2011)

© Habrahabr.ru