📜 ⬆️ ⬇️

Database Development with Code First

image

It is universally accepted that in “serious” CRUD applications the database becomes paramount. It is designed by the very first, it acquires stored procedures (stored procedures), it is necessary to tinker with it the most. But this is not the only way! For the Entity Framework, there is a Code First approach, where the code becomes the main, not the base. Benefits:


')
There are a couple of flaws, but they are more likely related to the Entity Framework, rather than the Code First approach as such; about them later.

Below I will show by example how easy it is to develop with the Code First approach.

Example

Take a simple model:

image

ASP.NET MVC will be the front-end, so create the corresponding project. We select No Authentication - in this project it will be impossible to log in and all content is accessible to all.

I have made 2 more projects - for business objects and DAL, but if you wish, you can simply create the appropriate folders in the web project. Do not forget to install the Entity Framework in the relevant projects through NuGet.

image


Create classes that will display entities (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<Enrollment> 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<Enrollment> 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; } } 


Apparently, all repeating properties (properties) can be removed in the abstract class and inherited from it. In this case, each table will have a Primary Key column of the Guid type, which will be generated when writing to the database.

Grade is just an enumerator, nothing special:
  public enum Grade { A,B,C,D,E,F } 


Create a context class:

  public class UniversityContext : DbContext { public UniversityContext() : base("UniversityContext") { } public DbSet<Course> Courses { get; set; } public DbSet<Enrollment> Enrollments { get; set; } public DbSet<Student> Students { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<Student>() .HasMany(s => s.Enrollments) .WithRequired(e => e.Student) .HasForeignKey(e => e.StudentID); modelBuilder.Entity<Course>() .HasMany(c => c.Enrollments) .WithRequired(e => e.Course) .HasForeignKey(e => e.CourseID); } } 


Relations are defined through the Fluent API, read from the end — for example, Student-Enrollment are treated as one (Student): many (Enrollment).

It is worth noting that the models can be configured through both the Fluent API and annotations. For some settings, annotations do not exist, but you can create them yourself . I prefer the Fluent API though.

And finally, filling the database:

  public class UniversityInitializer : System.Data.Entity.DropCreateDatabaseIfModelChanges<UniversityContext> { protected override void Seed(UniversityContext context) { var studentList = new List<Student>() { 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<Course>() { 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(c)); context.SaveChanges(); var enrollments = new List<Enrollment>() { 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(); } } 


Note : as the name implies DropCreateDatabaseIfModelChanges , the base will drop when changes are made in the corresponding classes of models. That is, the data - kaput.
How to implement migrations so that the data does not go far beyond the scope of this article.

The last thing to do is add the information to the web.config. Use LocalDb, which comes with Visual Studio, which is enough for the purposes of this project. The following code goes to the configuration element:

 <connectionStrings> <add name="UniversityContext" connectionString="Data Source=(LocalDb)\v11.0;;AttachDbFilename=|DataDirectory|\UnivCRUD.mdf;Initial Catalog=UniversityCRUD;Integrated Security=SSPI;" providerName="System.Data.SqlClient"/> </connectionStrings> 


And the following markup is in the entityFramework element:
 <contexts> <context type="UniversityCRUD.DA.UniversityContext, UniversityCRUD.DA"> <databaseInitializer type="UniversityCRUD.DA.UniversityInitializer, UniversityCRUD.DA" /> </context> </contexts> 


In the type attribute of the context element, the context class name and assembly, where this class is located, are separated by commas. The same for the initializer in the databaseInitializer element.

That's all, the project is ready to launch.

In Visual Studio 2013, you can quickly generate a Controller and View to the selected model via the Add -> New Scaffolded Item dialog.

image

Download an example here .

disadvantages

First, it is difficult to apply this approach to the existing database. So in general, this is for development from scratch.
Often the steps are set by the Entity Framework, which often makes decisions for the programmer — there are so-called conventions that, say, a property called Id will be converted to a Primary Key table by default. I do not like this approach.

Continuing the theme

Development using the Code First approach in the Entity Framework is quite a lengthy topic. I did not address the issue of migrations, problems with multithreading (concurrency) and much more. If the community is interested, I can continue this topic in further articles.

Materials:

1. Getting started with the 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)

Source: https://habr.com/ru/post/234827/


All Articles