Lesson Wednesday

Now that we've had some time to practice adding create and read functionality with Entity, we're ready to add update and delete functionality as well. In this lesson, we'll add update functionality. In the next lesson, we'll add the ability to delete items as well.

We'll start by updating our controller:

ItemsController.cs
using Microsoft.EntityFrameworkCore;

...
public ActionResult Edit(int id)
{
    var thisItem = _db.Items.FirstOrDefault(item => item.ItemId == id);
    return View(thisItem);
}

[HttpPost]
public ActionResult Edit(Item item)
{
    _db.Entry(item).State = EntityState.Modified;
    _db.SaveChanges();
    return RedirectToAction("Index");
}
...
  • Because we will be accessing something called EntityState in our controller action for updating an item, we first need to add a using directive for Microsoft.EntityFrameworkCore.

  • Next, we have both GET and POST Edit actions. The GET action will route to a page with a form for updating an item. The POST action will actually update the item. Don't forget that we need to include an [HttpPost] annotation above the POST action.

  • Like our Details method, the GET request uses a specific entry as the model for the page. In fact, the code in this action looks exactly the same as the code in the Details action. That's because it's doing the same thing: finding a specific item and then passing it to the view.

  • Our POST request has some new, unfamiliar code: _db.Entry(item).State = EntityState.Modified;. We find and update all of the properties of the item we are editing by passing the item (our route parameter) itself into the Entry() method. Then we need to update its State property to EntityState.Modified. This is so Entity knows that the entry has been modified, as it is not explicitly tracking it (we never actually retrieved the item from the database). Once we've marked this specific entry's state as Modified, we can then ask the database to SaveChanges() and finally redirect to the Index action.

For more on working with entity states, see the official documentation. As is often the case with Microsoft documentation, it is very dense.

Now we're ready to add a view with a form:

Views/Items/Edit.cshtml
@{
  Layout = "_Layout";
}

@model ToDoList.Models.Item

<h2>Edit</h2>

<h4>Edit this task: @Html.DisplayFor(model => model.Description)</h4>

@using (Html.BeginForm())
{
    @Html.HiddenFor(model => model.ItemId)

    @Html.LabelFor(model => model.Description)
    @Html.EditorFor(model => model.Description)

    <input type="submit" value="Save" />
}
<p>@Html.ActionLink("Back to list", "Index")</p>

This view is very similar to the Create.cshtml view we constructed together in the last lesson. However, there is a key new addition:

@Html.HiddenFor(model => model.ItemId)

This is because we need to pass the specific item's ItemId on to the controller. If we don't, our controller won't know which item to update.

Finally, let's add an edit link to Details.cshtml. That way, a user can go to a specific item's page and then click on a link to edit that item.

Views/Items/Details.cshtml
<p>@Html.ActionLink("Edit Item", "Edit", new { id = Model.ItemId })</p>

In this case, we need to specify that we are looking for the ItemId of the Model that is passed into this view.

Repository Reference

Follow the link below to view how a sample version of the project should look at this point. Note that this is a link to a specific commit in the repository.

Example GitHub Repo for To Do List

Controllers/ItemsController.cs

using Microsoft.AspNetCore.Mvc;
using ToDoList.Models;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;

namespace ToDoList.Controllers
{
  public class ItemsController : Controller
  {
    private readonly ToDoListContext _db;

    public ItemsController(ToDoListContext db)
    {
      _db = db;
    }

    public ActionResult Index()
    {
      List<Item> model = _db.Items.ToList();
      return View(model);
    }

    public ActionResult Create()
    {
      return View();
    }

    [HttpPost]
    public ActionResult Create(Item item)
    {
      _db.Items.Add(item);
      _db.SaveChanges();
      return RedirectToAction("Index");
    }

    public ActionResult Details(int id)
    {
      Item thisItem = _db.Items.FirstOrDefault(item => item.ItemId == id);
      return View(thisItem);
    }

    public ActionResult Edit(int id)
    {
      var thisItem = _db.Items.FirstOrDefault(item => item.ItemId == id);
      return View(thisItem);
    }

    [HttpPost]
    public ActionResult Edit(Item item)
    {
      _db.Entry(item).State = EntityState.Modified;
      _db.SaveChanges();
      return RedirectToAction("Index");
    }
  }
}

Views/Items/Edit.cshtml

@{
  Layout = "_Layout";
}

@model ToDoList.Models.Item

<h2>Edit</h2>

<h4>Edit this task: @Html.DisplayFor(model => model.Description)</h4>

@using (Html.BeginForm())
{
    @Html.HiddenFor(model => model.ItemId)

    @Html.LabelFor(model => model.Description)
    @Html.EditorFor(model => model.Description)

    <input type="submit" value="Save" />
}
<p>@Html.ActionLink("Back to list", "Index")</p>

Lesson 31 of 36
Last updated more than 3 months ago.