In this article, we will learn about CRUD (Create, Read, Update, Delete) functionality in ASP.NET MVC using Dapper. Let's run your application.
You can create a new author, delete or edit an existing author, and you can also see the details of any particular author using the highlighted links. But the views associated with these links are not available, and we need to add these views and update their respective actions in AuthorController
.
First, we will add a Details
view by right-clicking on Author folder and select Add > Views... option. It will open the Add New Scaffolded Item dialog, select the Razor View and enter the following details.
You will see the following code is added automatically for you in the Details.cshtml
file.
@model MvcWithDapper.Models.Author
@{
ViewData["Title"] = "Details";
}
<h1>Details</h1>
<div>
<h4>Author</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.AuthorId)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.AuthorId)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.FirstName)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.FirstName)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.LastName)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.LastName)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Address)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Address)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.City)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.City)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.PostalCode)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.PostalCode)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Country)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Country)
</dd>
</dl>
</div>
<div>
@Html.ActionLink("Edit", "Edit", new { /* id = Model.PrimaryKey */ }) |
<a asp-action="Index">Back to List</a>
</div>
Each field is displayed using a DisplayFor
helper, so here it will display the contents of the author in an HTML table.
Now let's update the Details
action method of AuthorController
to fetch the particular author from the database, as shown below.
// GET: AuthorController/Details/5
public ActionResult Details(int id)
{
string sqlAuthor = "SELECT * FROM Authors WHERE AuthorId = " + id + ";";
using (var connection = new SqlConnection("Data Source=(localdb)\\ProjectsV13;Initial Catalog=AuthorDb;Trusted_Connection=True;MultipleActiveResultSets=true"))
{
var author = connection.Query<Author>(sqlAuthor).FirstOrDefault();
return View(author);
}
}
Now run your application and go to the details page.
First, we will add a Create
view by right-clicking on the Author folder and select the Add > Views... option. It will open the Add New Scaffolded Item dialog, select the Razor View and enter the following details.
You will see the following code is added automatically for you in the Details.cshtml
file.
@model MvcWithDapper.Models.Author
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Author</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="AuthorId" class="control-label"></label>
<input asp-for="AuthorId" class="form-control" />
<span asp-validation-for="AuthorId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FirstName" class="control-label"></label>
<input asp-for="FirstName" class="form-control" />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="LastName" class="control-label"></label>
<input asp-for="LastName" class="form-control" />
<span asp-validation-for="LastName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Address" class="control-label"></label>
<input asp-for="Address" class="form-control" />
<span asp-validation-for="Address" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="City" class="control-label"></label>
<input asp-for="City" class="form-control" />
<span asp-validation-for="City" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="PostalCode" class="control-label"></label>
<input asp-for="PostalCode" class="form-control" />
<span asp-validation-for="PostalCode" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Country" class="control-label"></label>
<input asp-for="Country" class="form-control" />
<span asp-validation-for="Country" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
It uses labels, input, and span (for validation messages), tag helpers, for each field. This is server-side validation that you get by default.
In the above code, you will see the field for AuthorId
which we do not want, because we have an identity column in the database, so let's remove the following div
tag from the Create.cshtml
file.
<div class="form-group">
<label asp-for="AuthorId" class="control-label"></label>
<input asp-for="AuthorId" class="form-control" />
<span asp-validation-for="AuthorId" class="text-danger"></span>
</div>
Now let's update the Create
HttpPost
action method of AuthorController
to fetch the particular author from the database as shown below.
// POST: AuthorController/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind("FirstName,LastName,Address, City, PostalCode, Country")] Author author)
{
string sql = "INSERT INTO Authors (FirstName, LastName, Address, City, PostalCode, Country) VALUES (@FirstName, @LastName, @Address, @City, @PostalCode, @Country);";
try
{
if (ModelState.IsValid)
{
using (var connection = new SqlConnection("Data Source=(localdb)\\ProjectsV13;Initial Catalog=AuthorDb;Trusted_Connection=True;MultipleActiveResultSets=true"))
{
var affectedRows = connection.Execute(sql,
new
{
FirstName = author.FirstName,
LastName = author.LastName,
Address = author.Address,
City = author.City,
PostalCode = author.PostalCode,
Country = author.Country
});
return RedirectToAction("Index");
}
}
}
catch (Exception /* ex */)
{
//Log the error (uncomment ex variable name and write a log.
ModelState.AddModelError("", "Unable to save changes. " +
"Try again, and if the problem persists " +
"see your system administrator.");
}
return View(author);
}
Now run your application and go to the create page.
Enter the information of an author you want to add and click on the Create button, and you will see a new author is added to the list.
First, we will add an Edit
view by right-clicking on Author folder and select Add > Views... option. It will open the Add New Scaffolded Item dialog, select the Razor View and enter the following details.
You will see the following code is added automatically for you in the Edit.cshtml
file.
@model MvcWithDapper.Models.Author
@{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>Author</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="AuthorId" class="control-label"></label>
<input asp-for="AuthorId" class="form-control" />
<span asp-validation-for="AuthorId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FirstName" class="control-label"></label>
<input asp-for="FirstName" class="form-control" />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="LastName" class="control-label"></label>
<input asp-for="LastName" class="form-control" />
<span asp-validation-for="LastName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Address" class="control-label"></label>
<input asp-for="Address" class="form-control" />
<span asp-validation-for="Address" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="City" class="control-label"></label>
<input asp-for="City" class="form-control" />
<span asp-validation-for="City" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="PostalCode" class="control-label"></label>
<input asp-for="PostalCode" class="form-control" />
<span asp-validation-for="PostalCode" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Country" class="control-label"></label>
<input asp-for="Country" class="form-control" />
<span asp-validation-for="Country" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
In the above code, you will see the field for AuthorId
which we do not want, because we have an identity column in the database, so let's remove the following div
tag from the Create.cshtml
file.
<div class="form-group">
<label asp-for="AuthorId" class="control-label"></label>
<input asp-for="AuthorId" class="form-control" />
<span asp-validation-for="AuthorId" class="text-danger"></span>
</div>
Now we need to update both HttpGet
and HttpPost
Edit
actions. In HttpGet
Edit
action we will retrieve the specified author data and display it in the edit view.
// GET: AuthorController/Edit/5
public ActionResult Edit(int id)
{
string sqlAuthor = "SELECT * FROM Authors WHERE AuthorId = " + id + ";";
using (var connection = new SqlConnection("Data Source=(localdb)\\ProjectsV13;Initial Catalog=AuthorDb;Trusted_Connection=True;MultipleActiveResultSets=true"))
{
var author = connection.Query<Author>(sqlAuthor).FirstOrDefault();
return View(author);
}
}
To update the author data, we will also need to update the HttpPost
Edit
action, as shown below.
// POST: AuthorController/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, [Bind("FirstName,LastName,Address, City, PostalCode, Country")] Author author)
{
string sql = @"UPDATE Authors
SET FirstName = @FirstName,
LastName = @LastName,
Address = @Address,
City = @City,
PostalCode = @PostalCode,
Country = @Country
WHERE AuthorId = " + id + ";";
try
{
if (ModelState.IsValid)
{
using (var connection = new SqlConnection("Data Source=(localdb)\\ProjectsV13;Initial Catalog=AuthorDb;Trusted_Connection=True;MultipleActiveResultSets=true"))
{
var affectedRows = connection.Execute(sql,
new
{
FirstName = author.FirstName,
LastName = author.LastName,
Address = author.Address,
City = author.City,
PostalCode = author.PostalCode,
Country = author.Country
});
return RedirectToAction("Index");
}
}
}
catch (Exception /* ex */)
{
//Log the error (uncomment ex variable name and write a log.
ModelState.AddModelError("", "Unable to save changes. " +
"Try again, and if the problem persists " +
"see your system administrator.");
}
return View(author);
}
Now run your application and go to the edit page.
To update an author's information, here we will update the Address
field and click on the Save button, and you will see the specified author information is updated.
First, we will add a Delete
view by right-clicking on Author folder and select Add > Views... option. It will open the Add New Scaffolded Item dialog, select the Razor View and enter the following details.
You will see the following code is added automatically for you in the Delete.cshtml
file.
@model MvcWithDapper.Models.Author
@{
ViewData["Title"] = "Delete";
}
<h1>Delete</h1>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Author</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.AuthorId)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.AuthorId)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.FirstName)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.FirstName)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.LastName)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.LastName)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Address)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Address)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.City)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.City)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.PostalCode)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.PostalCode)
</dd>
<dt class = "col-sm-2">
@Html.DisplayNameFor(model => model.Country)
</dt>
<dd class = "col-sm-10">
@Html.DisplayFor(model => model.Country)
</dd>
</dl>
<form asp-action="Delete">
<input type="submit" value="Delete" class="btn btn-danger" /> |
<a asp-action="Index">Back to List</a>
</form>
</div>
In AuthorController
, the method that is called in response to a GET
request displays a view that gives the user a chance to approve or cancel the delete operation. In HttpGet
Edit
action we will retrieve the specified author data and display it in the delete view.
// GET: AuthorController/Delete/5
public ActionResult Delete(int id)
{
string sqlAuthor = "SELECT * FROM Authors WHERE AuthorId = " + id + ";";
using (var connection = new SqlConnection("Data Source=(localdb)\\ProjectsV13;Initial Catalog=AuthorDb;Trusted_Connection=True;MultipleActiveResultSets=true"))
{
var author = connection.Query<Author>(sqlAuthor).FirstOrDefault();
return View(author);
}
}
Replace the HttpPost
Delete
action method (named DeleteConfirmed) with the following code, which performs the actual delete operation and catches any database update errors.
// POST: AuthorController/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
string sql = "DELETE FROM Authors WHERE AuthorId = " + id + ";";
try
{
if (ModelState.IsValid)
{
using (var connection = new SqlConnection("Data Source=(localdb)\\ProjectsV13;Initial Catalog=AuthorDb;Trusted_Connection=True;MultipleActiveResultSets=true"))
{
var affectedRows = connection.Execute(sql);
return RedirectToAction("Index");
}
}
}
catch (Exception /* ex */)
{
//Log the error (uncomment ex variable name and write a log.
ModelState.AddModelError("", "Unable to save changes. " +
"Try again, and if the problem persists " +
"see your system administrator.");
}
return View();
}
Run the app, select the Authors tab, and click a Delete
hyperlink.
Now click on the Delete button, and you will see that the specified author is deleted from the list.