CRUD Operations in ASP.NET Core Using Entity Framework Core Code First
Introduction:
Here we are going to talk about how to perform the Create, Read, Update and Delete also called CRUD operations in Asp.Net Core. We will be using Code First development approach and create a database from model using migration.
Create Database:
Lets first install the Entity Framework Core in Our application. As we will be using SQL Server, install the package for SQL Server database provider. To Install the package follow the below steps:
- Tools >> Nuget Package >> Package Mangaer Console
- Run Package Manager >> Install-Package Microsoft.EntityFrameworkCore.SqlServer
Whenever we install a package in ASP.NET Core application, then the package installation occurs in the background. Restoring appears next to References in Solution Explorer while the installation occurs.
We use Entity Framework Core as an Object Relationship Mapper (ORM) to perform the CRUD operations. So Now let’s install the Entity Framework Core to maintain the database using the following procedure:
- Run PM from tools as earlier. Same process goes on to all packages when we need to install them. Install-package Microsoft.EntityFrameworkCore.Tools.
- Open project.json file.
Locate the tools section and add the ef command as shown below:
"tools": {
"BundlerMinifier.Core": "2.0.238",
"Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
}
Now, Lets Create two entities - the BaseEntity class that has common properties that will be inherited by each entity, and the Employee as shown in below snippet.
using System.Threading.Tasks;
namespace CRUDApplicationAsp.NetCore.Entities
{
public class BaseEntity
{
public Int64 Id { get; set; }
public DateTime AddedDate { get; set; }
public DateTime ModifiedDate { get; set; }
public string IPAddress { get; set; }
}
}
Now, create a Student entity under the DbEntities folder which inherits from the BaseEntity class. The following is a code for Student entity.
public class Student:BaseEntity
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string MobileNo { get; set; }
}
Now let us define the configuration for the Student Entity that will be used when the database table will be created by the entity. Below is the code for Student mapping entity (StudentMap.cs).
public class CustomerMap
{
public CustomerMap(EntityTypeBuilder<Customer> entityBuilder)
{
entityBuilder.HasKey(t => t.Id);
entityBuilder.Property(t => t.FirstName).IsRequired();
entityBuilder.Property(t => t.LastName).IsRequired();
entityBuilder.Property(t => t.Email).IsRequired();
entityBuilder.Property(t => t.MobileNo).IsRequired();
}
}
Use the Namespace Microsoft.EntityFrameworkCore.Metadata.Builders. Or simply you can point out the EntityTypeBuilder and press Ctrl + ‘.’ And Visual studio will provide you the appropriate namespace.
The EntityTypeBuilder<T> is an essential class which allows configuration to be performed for an entity type in a model. This is done using the modelbuilder in an override of the OnModelCreating method. The Constructor of the StudentMap class uses the Fluent API to map and configure properties in the table. So let's see each method used in the constructor one-by-one.
- HasKey()
The Haskey() method configures a primary key on table. - Property()
The Property method configures attributes for each property belonging to an entity or complex type. It is used to obtain a configuration object for a given property. The options on the configuration object are specific to the type being configured.
Now, it’s time to define context class. The ADO.NET Entity Framework Code First development approach requires us to create a data access context class that inherits from the DbContext class so we create a context class CRUDContext (CRUDContext.cs) class. In this class, we override the OnModelCreating() method. This method is called when the model for a context class (CRUDContext) has been initialized, but before the model has been locked down and used to initialize the context such that the model can be further configured before it is locked down. The following is the code snippet for the context class.
public class CRUDContext:DbContext
{
public CRUDContext(DbContextOptions<CRUDContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
new StudentMap(modelBuilder.Entity<Studetn>());
}
}
The Concept of dependency injection is central to the Asp.Net Core application that is why we register our context to dependency injection during the application start up. Once we register CRUDContext as a service to dependency injection then provide it through constructor to MVC Controller. In order for our MVC Controllers to make use of CRUDContext, we are going to register it as a service.
- Open the appsettings.json file and define connection string like below.
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=FM\\SQLEXPRESS;Initial Catalog=GYB_DB;User ID=sa; Password=versace"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
- Now, we can use the AddDbContext method to register it as a service. Locate the ConfigureServices method in StartUp class and add the codes to register it to dependency injection as per following code snippet.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddDbContext<CRUDContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
Use
- Microsoft.EntityFrameworkCore;
- CRUDApplication.DbEntities;
As the namespace.
Create a Model class StudentViewModel like below:
Model Creation is finished now we need to create database using migration. For this follow the following steps:
- Tools –>> NuGet Package Manager –>> Package Manager Console
- Run PM >> Add-Migration . This will ask a Migration Name. Provide whatever Name you want to. For now I’m using MyFirstMigration which is used to scaffold a migration to create the initial set of tables for our model. If we receive an error stating the term ‘add-migration’ is not recognized as the name of a cmdlet, then close and reopen Visual Studio
- Run PM> Update-Database to apply the new migration to the database. Because our database doesn’t exist yet, it will be created for us before the migration is applied.
Create Application User Interface
Now for the user Interface we need to create a controller.
Create a StudentController under the Controllers folder of Solution Explorer of the application. This controller has all ActionResult methods for each user interface of a CRUD operation. We first create a CRUDContext class instance then we inject it in the controller's constructor to get its object. The following is a code snippet for the StudentController.
using CRUDApplication.DbEntities;
using CRUDApplication.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
namespace CRUDApplication.Controllers
{
public class StudentController : Controller
{
private CRUDContext context;
public StudentController(CRUDContext context)
{
this.context = context;
}
[HttpGet]
public IActionResult Index()
{
IEnumerable<StudentViewModel> model = context.Set<Student>().ToList().Select(s => new StudentViewModel
{
Id= s.Id,
Name = $"{s.FirstName} {s.LastName}",
MobileNo = s.MobileNo,
Email = s.Email
});
return View("Index", model);
}
[HttpGet]
public IActionResult AddEditStudent(long? id)
{
StudentViewModel model = new StudentViewModel();
if (id.HasValue)
{
Student Student = context.Set<Student>().SingleOrDefault(c => c.Id == id.Value);
if (Student != null)
{
model.Id = Student.Id;
model.FirstName = Student.FirstName;
model.LastName = Student.LastName;
model.MobileNo = Student.MobileNo;
model.Email = Student.Email;
}
}
return PartialView("~/Views/Student/_AddEditStudent.cshtml", model);
}
[HttpPost]
public ActionResult AddEditStudent(long? id, StudentViewModel model)
{
try
{
if (ModelState.IsValid)
{
bool isNew = !id.HasValue;
Student Student = isNew ? new Student
{
AddedDate = DateTime.UtcNow
} : context.Set<Student>().SingleOrDefault(s => s.Id == id.Value);
Student.FirstName = model.FirstName;
Student.LastName = model.LastName;
Student.MobileNo = model.MobileNo;
Student.Email = model.Email;
Student.IPAddress = Request.HttpContext.Connection.RemoteIpAddress.ToString();
Student.ModifiedDate = DateTime.UtcNow;
if (isNew)
{
context.Add(Student);
}
context.SaveChanges();
}
}
catch (Exception ex)
{
throw ex;
}
return RedirectToAction("Index");
}
[HttpGet]
public IActionResult DeleteStudent(long id)
{
Student Student = context.Set<Student>().SingleOrDefault(c => c.Id == id);
StudentViewModel model = new StudentViewModel
{
Name = $"{Student.FirstName} {Student.LastName}"
};
return PartialView("~/Views/Student/_DeleteStudent.cshtml", model);
}
[HttpPost]
public IActionResult DeleteStudent(long id, FormCollection form)
{
Student Student = context.Set<Student>().SingleOrDefault(c => c.Id == id);
context.Entry(Student).State = Microsoft.EntityFrameworkCore.EntityState.Deleted;
context.SaveChanges();
return RedirectToAction("Index");
}
}
}
We can notice that the Controller takes a CRUDContext as a constructor parameter. ASP.NET dependency injection will take care of passing an instance of CRUDContext into our controller. The controller is developed to handle CURD operation requests for a Student entity. Now, let's develop the user interface for the CRUD operations. We develop it for the views for adding and editing a student, a student listing, student deletion. Let's see each one by one.
Student List View
This is the first view when the application is accessed or the entry point of the application is executed. It shows the student listing. We display student data in tabular format and on this view, we create links to add a new student, edit a student and delete a student. This view is an index view and the following is a code snippet for index.cshtml under the Student folder of Views.
@model IEnumerable<CRUDApplication.Models.StudentViewModel>
@using CRUDApplication.Models
@using CRUDApplication.Code
<div class="top-buffer"></div>
<div class="panel panel-primary">
<div class="panel-heading panel-head">Students</div>
<div class="panel-body">
<div class="btn-group">
<a id="createEditStudentModal" data-toggle="modal" asp-action="AddEditStudent" data-target="#modal-action-student" class="btn btn-primary">
<i class="glyphicon glyphicon-plus"></i> Add Customer
</a>
</div>
<div class="top-buffer"></div>
<table class="table table-bordered table-striped table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Mobile No</th>
<th>Action</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>@Html.DisplayFor(modelItem => item.Name)</td>
<td>@Html.DisplayFor(modelItem => item.Email)</td>
<td>@Html.DisplayFor(modelItem => item.MobileNo)</td>
<td>
<a id="editStudentModal" data-toggle="modal" asp-action="AddEditStudent" asp-route-id= "@item.Id" data-target="#modal-action-student"
class="btn btn-info">
<i class="glyphicon glyphicon-pencil"></i> Edit
</a>
<a id="deleteStudentModal" data-toggle="modal" asp-action="DeleteStudent" asp-route-id= "@item.Id" data-target="#modal-action-student" class="btn btn-danger">
<i class="glyphicon glyphicon-trash"></i> Delete
</a>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
@Html.Partial("_Modal", new BootstrapModel { ID = "modal-action-student", AreaLabeledId = "modal-action-student-label", Size = ModalSize.Medium })
@section scripts
{
<script src="~/js/student-index.js" asp-append-version="true"></script>
}
When we run the application and call the index() action with a HttpGet request, then we get all the students listed in the UI as below. CRUD operations are also available in this UI.
Create / Edit Customer View
Now we will Create a common view to create and edit a student so we create a single student view
Model. Code snippet of StudentViewModel is below:
public class StudentViewModel
{
public long Id { get; set; }
[Display(Name="First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
public string Name { get; set; }
public string Email { get; set; }
[Display(Name = "Mobile No")]
public string MobileNo { get; set; }
}
We will show form in bootstrap modal popup and submit using ajax post. That is why we need to create a javascript file which contains for removing loaded data.
(function ($) {
function Student() {
var $this = this;
function initilizeModel() {
$("#modal-action-customer").on('loaded.bs.modal', function (e) {
}).on('hidden.bs.modal', function (e) {
$(this).removeData('bs.modal');
});
}
$this.init = function () {
initilizeModel();
}
}
$(function () {
var self = new Student();
self.init();
})
}(jQuery))
Now, define a create/edit student partial view. Code snippet for _AddEditStudent.cshtml lies below:
@model CRUDApplication.Models.StudentViewModel
@using CRUDApplication.Models
<form asp-action="AddEditCustomer" role="form">
@await Html.PartialAsync("_ModalHeader", new ModalHeader { Heading = String.Format("{0} Customer", @Model.Id == 0 ? "Add" : "Edit") })
<div class="modal-body form-horizontal">
<div class="form-group">
<label asp-for="FirstName" class="col-lg-3 col-sm-3 control-label"></label>
<div class="col-lg-6">
<input asp-for="FirstName" class="form-control" />
</div>
</div>
<div class="form-group">
<label asp-for="LastName" class="col-lg-3 col-sm-3 control-label"></label>
<div class="col-lg-6">
<input asp-for="LastName" class="form-control" />
</div>
</div>
<div class="form-group">
<label asp-for="Email" class="col-lg-3 col-sm-3 control-label"></label>
<div class="col-lg-6">
<input asp-for="Email" class="form-control" />
</div>
</div>
<div class="form-group">
<label asp-for="MobileNo" class="col-lg-3 col-sm-3 control-label"></label>
<div class="col-lg-6">
<input asp-for="MobileNo" class="form-control" />
</div>
</div>
</div>
@await Html.PartialAsync("_ModalFooter", new ModalFooter { })
</form>
Now Run the application allocate the Index.cshtml page from StudentController. Add some information of students as show in below code snippet:
When it added it will be automatically be updated in database to check you database and there will be added information of student in Student Table. Like below:
Edit Students:
In the Table Click on Edit button to edit the information of student and click on Submit button. It will Edit the information and changes the value in the database too.
Delete Students
To delete informations of a student, we will need to click on the Delete button that exists in the Student listing data then a modal popup shows to ask “Are you want to delete xxx?” after clicking on the Delete button that exists in the popup view then it makes a HttpPost request that calls the DeleteStudent() action method and deletes the student. The following is a code snippet for _DeleteStudent.cshtml.
@model CRUDApplication.Models.StudentViewModel
@using CRUDApplication.Models
@using (Html.BeginForm())
{
@Html.Partial("_ModalHeader", new ModalHeader { Heading = "Delete Student" })
<div class="modal-body form-horizontal">
Are you want to delete @Model.Name?
</div>
@Html.Partial("_ModalFooter", new ModalFooter { SubmitButtonText = "Delete" })
}
In the Table when we click the Delete button, it pops up a window like in the figure below. Click again in Delete button to delete it permanently
Conclusion
We just looked at the CRUD operation i.e Create, Read, Update and Delete operation in ASP.NET CORE using Entity Framework Core with code first development approach. We used bootstrap CSS and Javascript for the User Interface Design to make it little bit attractive. Hope you will get along with it.