Practical Approach to Learn MVC: Part 4

In this article you will learn the basics of the MVC Model and how to modify the database table.

Introduction
 
This article is mostly non-theoretical.
 
This is the continuation following Part 3. If you are new to MVC then I will strongly recommend you to please go through part three before proceeding to this article. Click the following links for the previous parts of this tutorial.
In the last tutorial we saw the basics of Models and the Entity Framework Code First approach for CRUD operations on the database. I also discuss how to create databases and tables by migrating Entity Framework code. In this session we will first see how to edit rows and add new rows from an existing table using the Code First Approach of Entity Framework.
 
Add new rows from existing table
 
Open Visual Studio and go to your last project from this series and go to the Employee class under the models folder then use the following procedure.
 
Step 1
 
To add a new property to the Employee class go to the Employee class and add some properties. After adding some new properties now the Employee class will be as in the following.
  1. public class Employee  
  2. {  
  3.     public int Id { getset; }  
  4.     public string EmpName { getset; }  
  5.     public int Salary { getset; }  
  6.     public string Gender { getset; }  
  7.     public string MobileNo { getset; }  
  8.     public string EmailId { getset; }  
  9.     public DateTime  EmpDOB { getset; }  
  10. }  
Step 2
 
Build the project now. We have added two new properties in our existing Employee class. Now go to Configuration.cs under the Migrations folder and edit the employee seeder by adding those two property default values to that list. Now the Seed method will look something as in the following.
  1. protected override void Seed(CodeFirstApproachWithEmployeesInfo.Models.EmployeeDBContext context)  
  2. {  
  3.        context.Employees.AddOrUpdate(i => i.EmpName,  
  4.         new Employee  
  5.         {  
  6.             EmpName = "Manish Kumar",  
  7.             Salary = 30000,  
  8.             MobileNo = "9999999999",  
  9.             EmailId = "manish@live.com",  
  10.             Gender = "Male",  
  11.             EmpDOB = Convert.ToDateTime("07/12/1990")  
  12.         },  
  13.         new Employee  
  14.         {  
  15.             EmpName = "Namit Kumar",  
  16.             Salary = 20000,                      
  17.             Gender = "Male",  
  18.             MobileNo = "8888888888",  
  19.             EmailId = "namit@live.com",  
  20.             EmpDOB = Convert.ToDateTime("07/11/1988")                      
  21.         },  
  22.         new Employee  
  23.         {  
  24.             EmpName = "Vekat Kumar",  
  25.             Salary = 25000,  
  26.             Gender = "Male",  
  27.             MobileNo = "777777777777",  
  28.             EmailId = "Vekat@live.com",  
  29.             EmpDOB = Convert.ToDateTime("07/01/1980")                    
  30.         }  
  31.         );  
  32. }   
Step 3
 
Build the project and then go to your Package Manager Console and execute the following command.
 
Update-database
 
Update database 
 
For resolving the preceding error we need to enable the following property as true in the Configuration.cs file.
  1. public Configuration()  
  2. {  
  3.    AutomaticMigrationsEnabled = true;  
  4.    AutomaticMigrationDataLossAllowed = true;  
  5. }  
Enable both the property true and the first property will allow auto migration if the model changes and the AutomaticMigrationDataLossAllowed will allow data loss if the model changes.
 
Step 4
 
Thant's it. Run the project and all the changes will be reflected into the database. But when the view appears it will not contain all the required changes. Because we did not change the views. To change the view and the controller action method there are the following two methods. 
  • Edit the view and controller action method manually.
  • Drop and recreate the controller again.
In the preceding example we only add two properties so I will change each and every view manually step-by-step.
 
Index View: Go to the index view under the Views -> Employees folder and edit it to use the following code.
  1. <table class="table">  
  2.     <tr>  
  3.         <th>  
  4.             @Html.DisplayNameFor(model => model.EmpName)  
  5.         </th>  
  6.         <th>  
  7.             @Html.DisplayNameFor(model => model.Salary)  
  8.         </th>  
  9.          
  10.         <th>  
  11.             @Html.DisplayNameFor(model => model.Gender)  
  12.         </th>  
  13.         <th>  
  14.             @Html.DisplayNameFor(model => model.MobileNo)  
  15.         </th>  
  16.         <th>  
  17.             @Html.DisplayNameFor(model => model.EmailId)  
  18.         </th>  
  19.         <th>  
  20.             @Html.DisplayNameFor(model => model.EmpDOB)  
  21.         </th>  
  22.         <th>  
  23.             Action  
  24.         </th>  
  25.     </tr>  
  26.   
  27. @foreach (var item in Model) {  
  28.     <tr>  
  29.         <td>  
  30.             @Html.DisplayFor(modelItem => item.EmpName)  
  31.         </td>  
  32.         <td>  
  33.             @Html.DisplayFor(modelItem => item.Salary)  
  34.         </td>  
  35.         <td>  
  36.             @Html.DisplayFor(modelItem => item.Gender)  
  37.         </td>  
  38.         <td>  
  39.             @Html.DisplayFor(modelItem => item.MobileNo)  
  40.         </td>  
  41.         <td>  
  42.             @Html.DisplayFor(modelItem => item.EmailId)  
  43.         </td>  
  44.         <td>  
  45.             @Html.DisplayFor(modelItem => item.EmpDOB)  
  46.         </td>  
  47.         <td>  
  48.             @Html.ActionLink("Edit""Edit"new { id=item.Id }) |  
  49.             @Html.ActionLink("Details""Details"new { id=item.Id }) |  
  50.             @Html.ActionLink("Delete""Delete"new { id=item.Id })  
  51.         </td>  
  52.     </tr>  
  53. }  
  54.   
  55. </table>  
Run the index view and you will get the following screen.
 
index 
 
Create View: Here when you click Create New again it will not show the Mobile No and Email id fields so go to Create View and add some manual code there. Go and add the following code to your create view.
  1. <div class="form-group">  
  2.             @Html.LabelFor(model => model.EmailId, htmlAttributes: new { @class = "control-label col-md-2" })  
  3.             <div class="col-md-10">  
  4.                 @Html.EditorFor(model => model.EmailId, new { htmlAttributes = new { @class = "form-control" } })  
  5.                 @Html.ValidationMessageFor(model => model.EmailId, ""new { @class = "text-danger" })  
  6.             </div>  
  7.         </div>  
  8.         <div class="form-group">  
  9.             @Html.LabelFor(model => model.EmpDOB, htmlAttributes: new { @class = "control-label col-md-2" })  
  10.             <div class="col-md-10">  
  11.                 @Html.EditorFor(model => model.EmpDOB, new { htmlAttributes = new { @class = "form-control" } })  
  12.                 @Html.ValidationMessageFor(model => model.EmpDOB, ""new { @class = "text-danger" })  
  13.             </div>  
  14.         </div>  
Then go to the Employee controller and find the create action method decorated with [HttpPost] attributes and edit that method like follows.
  1. [HttpPost]  
  2.         [ValidateAntiForgeryToken]  
  3.         public ActionResult Create([Bind(Include = "Id,EmpName,Salary,Gender,MobileNo,EmailId,EmpDOB")] Employee employee)  
  4.         {  
  5.             if (ModelState.IsValid)  
  6.             {  
  7.                 db.Employees.Add(employee);  
  8.                 db.SaveChanges();  
  9.                 return RedirectToAction("Index");  
  10.             }  
  11.   
  12.             return View(employee);  
  13.         }   
Here what I am doing is basically adding both of the properties here (Bind(Include = "Id,EmpName,Salary,Gender,MobileNo,EmailId,EmpDOB")) and the rest will be the same. Now run this view and you can now add a mobile number and email id using this view.
 
In the same way you can edit the Edit view also with the preceding procedure. In the edit view you must do something with [Bind(Include = "Id,EmpName,Salary,Gender,MobileNo,EmailId,EmpDOB")] in the controller method decorated with [HttpPost] and Delete and Details. You just must add a label. For a better understanding download the code.
 
In the preceding example we saw how to add properties inside the Employee class. What happens if we want to create a new department and establish a one-to-many relationship with the Department and Employee tables? Let's see it with an example. 
 
Add new table and establish relationship with table.
 
We need to go through following procedure to add new table and defend the relationship with them. 
 
Step 1
 
Go to employee class and add another class Department like follows. 
  1. public class Department  
  2. {  
  3.     public int DeptId { getset; }  
  4.     public string DeptName { getset; }  
  5.     public IEnumerable<Employee> Employees { getset; }  
  6. }  
Edit the employee class also;
  1. public class Employee  
  2. {  
  3.     public int Id { getset; }  
  4.     public string EmpName { getset; }  
  5.     public int Salary { getset; }  
  6.     public string Gender { getset; }  
  7.     public string MobileNo { getset; }  
  8.     public string EmailId { getset; }  
  9.     public DateTime EmpDOB { getset; }  
  10.     [Required]  
  11.     [ForeignKey("Department")]  
  12.     public int DeptId { getset; }  
  13.     public virtual Department Department { getset; }  
  14. }  
Note: Here if you not write [ForeignKey("Department")] public int DeptId { get; set; } then also foreign key relationship will be created but the name of that foreign key field will be default name given by the Entity Framework. The preceding line will just change the default name of the foreign key to DeptId.
 
Step 2
 
When both class is ready go to EmployeeDBContext and add the DbSet<Departments> there like:
  1. public class EmployeeDBContext : DbContext  
  2. {  
  3.     public DbSet<Employee> Employees { getset; }  
  4.     public DbSet<Department> Departments { getset; }  
  5. }  
  6. Add following method  
  7. protected override void OnModelCreating(DbModelBuilder modelBuilder)  
  8. {  
  9.     Database.SetInitializer(new MigrateDatabaseToLatestVersion<EmployeeDBContext, Configuration>());  
  10. }  
The preceding method will execute when model will be creating. You need to add following name spaces also;
  1. using CodeFirstApproachWithEmployeesInfo.Migrations;  
Step 3
 
Build the project and go to Configuration.cs asn modify the default list by using following code.
  1. public Configuration()  
  2. {  
  3.     AutomaticMigrationsEnabled = true;  
  4.     AutomaticMigrationDataLossAllowed = true;  
  5. }  
  6.   
  7. protected override void Seed(CodeFirstApproachWithEmployeesInfo.Models.EmployeeDBContext context)  
  8. {  
  9.     //  This method will be called after migrating to the latest version.  
  10.   
  11.     //  You can use the DbSet<T>.AddOrUpdate() helper extension method   
  12.     //  to avoid creating duplicate seed data. E.g.  
  13.     context.Departments.AddOrUpdate(i => i.DeptName,  
  14.           new Department  
  15.           {  
  16.               DeptName = "IT"  
  17.           },  
  18.           new Department  
  19.           {  
  20.               DeptName = "HR"  
  21.           },  
  22.           new Department  
  23.           {  
  24.               DeptName = "Accounts"  
  25.           }  
  26.           );  
  27.     context.SaveChanges();  
  28.     context.Employees.AddOrUpdate(i => i.EmpName,  
  29.         new Employee  
  30.         {  
  31.             EmpName = "Manish Kumar",  
  32.             Salary = 30000,  
  33.             MobileNo = "9999999999",  
  34.             EmailId = "manish@live.com",  
  35.             Gender = "Male",  
  36.             EmpDOB = Convert.ToDateTime("07/12/1990"),  
  37.             DeptId = context.Departments.Single(x => x.DeptName == "IT").DeptId  
  38.         },  
  39.         new Employee  
  40.         {  
  41.             EmpName = "Namit Kumar",  
  42.             Salary = 20000,  
  43.             MobileNo = "9999999999",  
  44.             EmailId = "manish@live.com",  
  45.             Gender = "Male",  
  46.             EmpDOB = Convert.ToDateTime("07/11/1988"),  
  47.             DeptId = context.Departments.Single(x => x.DeptName == "IT").DeptId  
  48.         },  
  49.         new Employee  
  50.         {  
  51.             EmpName = "Vekat Kumar",  
  52.             Salary = 25000,  
  53.             MobileNo = "9999999999",  
  54.             EmailId = "manish@yahoo.com",  
  55.             Gender = "Male",  
  56.             EmpDOB = Convert.ToDateTime("07/01/1980"),  
  57.             DeptId = context.Departments.Single(x => x.DeptName == "HR").DeptId  
  58.         },  
  59.         new Employee  
  60.         {  
  61.             EmpName = "Kirti Sharma",  
  62.             Salary = 40000,  
  63.             MobileNo = "222222222222",  
  64.             EmailId = "kirti@gmail.com",  
  65.             Gender = "Male",  
  66.             EmpDOB = Convert.ToDateTime("07/12/1993"),  
  67.             DeptId = context.Departments.Single(x => x.DeptName == "Accounts").DeptId  
  68.         }  
  69.         );  
  70.     context.SaveChanges();  
  71. }  
If you did not make these AutomaticMigrationsEnabled = true; AutomaticMigrationDataLossAllowed = true; properties true then there must be an error.
 
Step 4
 
Then build the project and go to Package Manager Console and run following command.
 
Update-database -TargetMigration:0
 
That it run the project all the tables with defined relationship will be created check that in SQL Server. Now we need to modify the views and controller action method. If you want to modify it manually you can here I am just dropping the Employee controller and employees view folder and recreating it. In last session I have explained how to create controller and views if you are new to it just go through that first.
 
Now run the project and try to navigate the Index view of the employees controller or you can open the Index view by clicking Views folder and going to employees folder and clicking to Index.cshtml and then press ctrl+F5.
 
Here notice the design of the view. It has been change automatically. The Entity Framework is smart enough for creating the views based on the structure of the database table and controller action method.
 
Note: Note I have mark virtual ICollections<> for the property to create relationship this is because 
 
Lazy Loading: Any virtual ICollections will be lazy-loaded unless you specifically mark them otherwise.
 
More efficient change tracking
 
If you meet all the following requirements then your change tracking can use a more efficient method by hooking your virtual properties.
 
To get change tracking proxies, the basic rule is that your class must be public, non-abstract or non-sealed. Your class must also implement public virtual getters/setters for all properties that are persisted. Finally, you must declare collection based relationship navigation properties as ICollection<T> only. They cannot be a concrete implementation or another interface that derives from ICollection<T> (a difference from the Deferred Loading proxy)
 
If you are new to create relationship in Entity Framework code first approach click here for detail.
 
That's it for today. In our next session we will discuss how to customize these views depending on our need.
 
Summary
 
In this illustration you came to understand the basics of the MVC Model and how to modify the database table and defend the relationship among those tables using the Entity Framework Code First Approach.
 
Thanks.
 
I would like to get feedback from my readers. Please post your feedback, question, or comments about this article.