📜 ⬆️ ⬇️

Training course. Creating the Entity Framework data model for an ASP.NET MVC application

Using the example of a web application for Contoso University, we will demonstrate the creation of ASP.NET MVC applications using the Entity Framework, the functionality of which will include such features as accepting students, creating courses and appointing teachers.

These learning materials will be explained step by step through the process of creating a web application for Contoso University. You can download the finished application or create it according to the given sequence of steps. Examples are given in C #, code examples are available in C # and VB. If you have questions that are indirectly related to training materials, you can ask them on the ASP.NET Entity Framework forum or the Entity Framework and LINQ to Entities forum .

Training implies having knowledge of working with ASP.NET MVC in Visual Studio, otherwise a good place to start learning ASP.NET MVC Tutorial . If you prefer to work with ASP.NET Web Forms, take a look at Getting Started with the Entity Framework and Continuing with the Entity Framework .
')
Before you begin, make sure that you have the following software installed:

The contoso university


The application you develop is a simple university website.

clip_image001

Users will be able to view and update data on students, courses and teachers. A few screenshots of what happens below.

clip_image002

clip_image003

clip_image004

The UI is close in style to what is generated by default templates, so the focus will be on using the Entity Framework.

Development Approaches with the Entity Framework


Ishoy from the diagram, there are three approaches to working with data in the Entity Framework: Database First , Model First , and Code First.

clip_image005

Database first

In the case of an existing database, the Entity Framework can automatically create a data model consisting of classes and properties that correspond to database objects (such as tables and columns). Information about the database structure (store schema), data model ( conceptual model ) and mapping them onto each other is contained in XML in the .edmx file. Visual Studio provides the graphic designer Entity Framework, with which you can view and edit .edmx . The parts of Getting Started With the Entity Framework and Continuing With the Entity Framework in the Web Forms materials use the Database First approach.

Model first

If there is no base, you can start by creating a data model using the Visual Studio Entity Framework designer. After completing work on the model, the designer will generate a DDL ( data definition language ) code for creating the database. In this approach, .edmx is also used to store information about the model and mappings . What's New in the Entity Framework 4 includes a small sample development using this approach.

Code first

Regardless of the presence of the database, you can manually write the code of classes and properties corresponding to the entities in the database and use this code with the Entity Framework without using a file . edmx That is why you can sometimes see how this approach is called code only , although the official name Code First. Mapping between the store schema and the conceptual model in the mapping API. If there is no base yet, the Entity Framework can create, delete or recreate it in case of changes in the model.

The data access API developed for Code First is based on the DbContext class. The API can also be used in the development process with Database First and Model First approaches. For more information, see When is Code First not code first? In the blog of the development team Entity Framework.

POCO (Plain Old CLR Objects)


By default, for the Database First and Model First approaches, the data model classes are inherited from EntityObject , which provides the Entity Framework functionality. This means that these classes are not persistence ignorant and, thus, do not fully meet one of the conditions of the domain-driven design . All approaches to development with the Entity Framework can also work with POCO ( plain old CLR objects ), which, in general, means that they are persistence-ignorant due to the lack of EntityObject inheritance.

Create MVC Web Application


Open Visual Studio and create a new "ContosoUniversity" project using the ASP.NET MVC 3 Web Application :

clip_image006

In New ASP. NET MVC 3 Project, select the Internet Application template and the Razor view engine, uncheck the Create a unit test project and click OK .

clip_image007

Customize styles

A few small amendments will change the site menu, the layout of elements and the home page.

To customize the Contoso University menu, in Views \ Shared \ _ Layout. cshtml replace the text in h 1 and the links in the menu, as in the example:

 <!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script> </head> <body> <div class="page"> <div id="header"> <div id="title"> <h1>Contoso University</h1> </div> <div id="logindisplay"> @Html.Partial("_LogOnPartial") </div> <div id="menucontainer"> <ul id="menu"> <li>@Html.ActionLink("Home", "Index", "Home")</li> <li>@Html.ActionLink("About", "About", "Home")</li> <li>@Html.ActionLink("Students", "Index", "Student")</li> <li>@Html.ActionLink("Courses", "Index", "Course")</li> <li>@Html.ActionLink("Instructors", "Index", "Instructor")</li> <li>@Html.ActionLink("Departments", "Index", "Department")</li> </ul> </div> </div> <div id="main"> @RenderBody() </div> <div id="footer"> </div> </div> </body> </html> 

In Views \ Home \ Index.cshtml delete everything in the h2 tag.

In Controllers \ HomeController.cs, replace "Welcome to ASP.NET MVC!" on "Welcome to Contoso University!"

In Content \ Site. css to shift the menu to the left, make the following changes:

 #main { clear: both; padding: 30px 30px 15px 30px; background-color: #fff; border-radius: 4px 0 0 0; -webkit-border-radius: 4px 0 0 0; -moz-border-radius: 4px 0 0 0; } 

 nav, #menucontainer { margin-top: 40px; clear: both; float: left; } 

Run the project.

clip_image001[1]

Creating a data model


Next, create the first entity classes for Contoso University. We will start with the following three entities:

clip_image008

A one-to-many relationship is established between the entities Student and Enrollment , and a one-to-many relationship between Course and Enrollment . In other words, a student can attend any number of courses, and a course can have any number of students attending it.

In the future, you will create classes for each of these entities.

Note: compiling a project without classes created for these entities will cause compiler errors.

Entity Student

clip_image009

In the Models folder, create a Student. cs and replace the generated code with:

 using System; using System.Collections.Generic; namespace ContosoUniversity.Models { public class Student { public int StudentID { get; set; } public string LastName { get; set; } public string FirstMidName { get; set; } public DateTime EnrollmentDate { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; } } } 

The StudentID property will be the primary key of the corresponding table. By default, the Entity Framework treats a property with an ID or classname ID as the primary key.

Enrollments - navigation property . Navigation properties contain other entities related to the current. In this case, the Enrollments property contains all the Enrollment entities associated with the current Student entity. In other words, if a certain Student record in a database has a link to two Enrollment records (records containing primary key values ​​for a student in the StudentID foreign key StudentID ), the property of this Enrollments record will contain two Enrollment entities.

Navigation properties are usually marked with a virtual modifier to use the Entity Framework feature called lazy loading . (the essence of Lazy loading will be explained later, in Reading Related Data ) If the navigation property can contain several entities (in many-to-many and one-to-many relationships), its type should be an ICollection .

Entity Enrollment

clip_image010

In the Models folder, create an Enrollment. cs with the following content:

 using System; using System.Collections.Generic; namespace ContosoUniversity.Models { public class Enrollment { public int EnrollmentID { get; set; } public int CourseID { get; set; } public int StudentID { get; set; } public decimal? Grade { get; set; } public virtual Course Course { get; set; } public virtual Student Student { get; set; } } } 

The question mark after specifying the decimal type indicates that the Grade property is nullable. A rating set to null is different from a zero rating — null means that the rating has not been set yet, whereas 0 is already a value.

The StudentID property is a foreign key, and the corresponding navigation property Student . The entity Enrollment associated with one Student entity, therefore a property can contain only one entity of the specified type (as opposed to Student . Enrollments ).

The CourseID property is a foreign key, and the corresponding navigation property Course . Entity Enrollment associated with one Entity Course .

Essence Course

clip_image011

In the Models folder, create a Course. cs with the following content:

 using System; using System.Collections.Generic; namespace ContosoUniversity.Models { public class Course { public int CourseID { get; set; } public string Title { get; set; } public int Credits { get; set; } public virtual ICollection<Enrollment> Enrollments { get; set; } } } 

Enrollments - navigation property. Entity Course can be associated with an infinite set of Enrollment entities.

Creating Database Context


The main class coordinating the Entity Framework functionality for the current data model is called the database context . This class is inherited from System . Data . Entity . DbContext . In the code, you define which entities to include in the data model, and you can also define the behavior of the Entity Framework itself. In our code, this class is called SchoolContext .

Create a folder DAL and in it a new class SchoolContext. cs :

 using System; using System.Collections.Generic; using System.Data.Entity; using ContosoUniversity.Models; using System.Data.Entity.ModelConfiguration.Conventions; namespace ContosoUniversity.Models { public class SchoolContext : DbContext { public DbSet<Student> Students { get; set; } public DbSet<Enrollment> Enrollments { get; set; } public DbSet<Course> Courses { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); } } } 

The code creates a DbSet property for each set of entities. In Entity Framework terminology, an entity set refers to a database table, and an entity refers to an entry in a table.

OnModelCreating protects table names from pluralization, and if you don’t do this, you get table names such as Students , Courses , Enrollments . Otherwise, the table names will be Student , Course , Enrollment . Developers are arguing about whether the names of tables should be pluralized or not. We use a single form, but the important thing is that you can choose whether to include this line in the code or not.

(This class is in Models namespace because in some situations the Code First approach implies finding the entity classes and context in the same namespace.)

Definition of a Connection String


You do not need to define a connection string. If you have not defined this line, the Entity Framework will automatically create a SQL Server Express database. However, we will work with SQL Server Compact, and you will need to create a connection string indicating this.

Open the web. config and add a new connection string to the connectionStrings collection. (Make sure you update the Web. Config in the root of the project, as there is another Web. Config in the Views folder that you don’t need to touch .)

 <add name="SchoolContext" connectionString="Data Source=|DataDirectory|School.sdf" providerName="System.Data.SqlServerCe.4.0"/> 

By default, the Entity Framework looks for a connection string, also called an object context class. The connection string that you added defines the School.sdf database, located in the App_data folder and in SQL Server Compact.

Database initialization with test data


Entity Framework can automatically create a database when you start the application. You can specify that this should occur every time the application is launched or only when the model is out of sync with the existing database. You can also write a class with a method that the Entity Framework will automatically call before creating a base for use with test data. We will indicate that the base should be deleted and re-created when the model changes.

In the DAL folder, create a new SchoolInitializer class . cs with the code with which the database will be created, if necessary, and filled with test data.

 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data.Entity; using ContosoUniversity.Models; namespace ContosoUniversity.DAL { public class SchoolInitializer : DropCreateDatabaseIfModelChanges<SchoolContext> { protected override void Seed(SchoolContext context) { var students = new List<Student> { new Student { FirstMidName = "Carson", LastName = "Alexander", EnrollmentDate = DateTime.Parse("2005-09-01") }, new Student { FirstMidName = "Meredith", LastName = "Alonso", EnrollmentDate = DateTime.Parse("2002-09-01") }, new Student { FirstMidName = "Arturo", LastName = "Anand", EnrollmentDate = DateTime.Parse("2003-09-01") }, new Student { FirstMidName = "Gytis", LastName = "Barzdukas", EnrollmentDate = DateTime.Parse("2002-09-01") }, new Student { FirstMidName = "Yan", LastName = "Li", EnrollmentDate = DateTime.Parse("2002-09-01") }, new Student { FirstMidName = "Peggy", LastName = "Justice", EnrollmentDate = DateTime.Parse("2001-09-01") }, new Student { FirstMidName = "Laura", LastName = "Norman", EnrollmentDate = DateTime.Parse("2003-09-01") }, new Student { FirstMidName = "Nino", LastName = "Olivetto", EnrollmentDate = DateTime.Parse("2005-09-01") } }; students.ForEach(s => context.Students.Add(s)); context.SaveChanges(); var courses = new List<Course> { new Course { Title = "Chemistry", Credits = 3, }, new Course { Title = "Microeconomics", Credits = 3, }, new Course { Title = "Macroeconomics", Credits = 3, }, new Course { Title = "Calculus", Credits = 4, }, new Course { Title = "Trigonometry", Credits = 4, }, new Course { Title = "Composition", Credits = 3, }, new Course { Title = "Literature", Credits = 4, } }; courses.ForEach(s => context.Courses.Add(s)); context.SaveChanges(); var enrollments = new List<Enrollment> { new Enrollment { StudentID = 1, CourseID = 1, Grade = 1 }, new Enrollment { StudentID = 1, CourseID = 2, Grade = 3 }, new Enrollment { StudentID = 1, CourseID = 3, Grade = 1 }, new Enrollment { StudentID = 2, CourseID = 4, Grade = 2 }, new Enrollment { StudentID = 2, CourseID = 5, Grade = 4 }, new Enrollment { StudentID = 2, CourseID = 6, Grade = 4 }, new Enrollment { StudentID = 3, CourseID = 1 }, new Enrollment { StudentID = 4, CourseID = 1, }, new Enrollment { StudentID = 4, CourseID = 2, Grade = 4 }, new Enrollment { StudentID = 5, CourseID = 3, Grade = 3 }, new Enrollment { StudentID = 6, CourseID = 4 }, new Enrollment { StudentID = 7, CourseID = 5, Grade = 2 }, }; enrollments.ForEach(s => context.Enrollments.Add(s)); context.SaveChanges(); } } } 

The Seed method accepts a database context object as an input parameter and uses it to add new entities to the database. For each type of entity, the code creates a collection of new entities, adding them to the corresponding DbSet property, and then saves the changes to the database. There is no need to call SaveChanges after each group of entities, as we have done, but it helps to identify the problem in case of exceptions.

Change Global. asax. cs so that our code is called every time the application is started:

 using System.Data.Entity; using ContosoUniversity.Models; using ContosoUniversity.DAL; 

 Database.SetInitializer<SchoolContext>(new SchoolInitializer()); 

The application is configured in such a way that each time the database is accessed after launching the application, the Entity Framework compares the base with the model ( SchoolContext class), and if it is out of sync, the application deletes and re-creates the base.

Note when deploying an application to a production server, you must remove all code that initializes the database with test data.

Next, you will create a web page to display the data, and the data query process automatically initiates the creation of the database. You will start with a new controller, but before that, build the project so that the model and context classes are available for MVC controller scaffolding.

Creating a Student Controller


To create a Student controller, click on the Controllers folder in Solution Explorer , click Add , Controller . In Add Controller, perform the following actions and changes and click Add :

clip_image012

Open Controllers \ StudentController. cs , you will see the created variable initializing the database context object:

  private SchoolContext db = new SchoolContext (); 

The Index action collects a list of students from the Students property from an instance of the database context:

 public ViewResult Index() { return View(db.Students.ToList()); } 

Automatic scaffolding was created for the Student set. To customize the headings and column sequence, open Views \ Student \ Index. cshtml and replace the code with:

 @model IEnumerable<ContosoUniversity.Models.Student> @{ ViewBag.Title = "Students"; } <h2>Students</h2> <p> @Html.ActionLink("Create New", "Create") </p> <table> <tr> <th></th> <th>Last Name</th> <th>First Name</th> <th>Enrollment Date</th> </tr> @foreach (var item in Model) { <tr> <td> @Html.ActionLink("Edit", "Edit", new { id=item.StudentID }) | @Html.ActionLink("Details", "Details", new { id=item.StudentID }) | @Html.ActionLink("Delete", "Delete", new { id=item.StudentID }) </td> <td> @Html.DisplayFor(modelItem => item.LastName) </td> <td> @Html.DisplayFor(modelItem => item.FirstMidName) </td> <td> @Html.DisplayFor(modelItem => item.EnrollmentDate) </td> </tr> } </table> 

Launch the site, click on the Students tab.

clip_image002[1]

Close the browser. In Solution Explorer, select the ContosoUniversity project . Click Show all Files , Refresh and then expand the App_Data folder.

clip_image013

Double-click on School. sdf to open Server Explorer , and Tables .

Note If you get an error after you double-click on School.sdf, make sure you have installed Visual Studio 2010 SP1 Tools for SQL Server Compact 4.0 . If everything is installed, restart Visual Studio.

clip_image014

Each table has its own set of entities + one additional table. EdmMetadata used to define the Entity Framework when model and base have become unsynchronized.

Click on one of the tables and Show Table Data to see the data loaded by the SchoolInitializer class.

clip_image015

Close the connection, otherwise there may be a problem running the application.

clip_image016

Agreements


The amount of code needed to create the Entity Framework database is minimal due to the use of ( conventions) Entity Framework. Some of them have already been mentioned:

You have seen that these agreements can be overridden (for example, you can turn off pluralization) and you can learn more about how to do this from Creating a More Complex Data Model .

You created a simple application using the Entity Framework and SQL Server Compact to store and display data. Next, we will learn how to perform simple CRUD (create, read, update, delete) operations.

Thanks for the help in the translation of Alexander Belotserkovsky ( ahriman ).

Download all app | Download the manual in PDF format

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


All Articles