Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
В предыдущей теме мы посмотрели, как редактировать данные. Продолжим работу с моделью Book и теперь посмотрим, как мы можем ее добавлять и удалить из БД. Для добавления данных вначале определим пару действий:
[HttpGet] public ActionResult Create() { return View(); } [HttpPost] public ActionResult Create(Book book) { db.Books.Add(book); db.SaveChanges(); return RedirectToAction("Index"); }
Первый метод возвращает пользователю представление с формой для добавления, а второй - принимает данные этой формы. Теперь создадим представление.
А представление будет выглядеть следующим образом:
@model BookStore.Models.Book @{ Layout = "~/Views/Shared/_Layout.cshtml"; } <h2>Новая книга</h2> @using (Html.BeginForm()) { @Html.LabelFor(model => model.Name, "Название книги") <br /> @Html.EditorFor(model => model.Name) <br /><br /> @Html.LabelFor(model => model.Author, "Автор") <br /> @Html.EditorFor(model => model.Author) <br /><br /> @Html.LabelFor(model => model.Price, "Цена") <br /> @Html.EditorFor(model => model.Price) <br /><br /> <input type="submit" value="Добавить" /> }
При получении объекта book в действии Create метод db.Books.Add(book)
будет устанавливать значение Added
в качестве состояния
объекта модели. Поэтому метод db.SaveChanges()
сгенерирует выражение INSERT для вставки данных модели в таблицу. То есть метод Create мы могли
бы переписать следующим образом:
[HttpPost] public ActionResult Create(Book book) { db.Entry(book).State = EntityState.Added; db.SaveChanges(); return RedirectToAction("Index"); }
Теперь самая важная часть - удаление данных. Даже не в плане реализации, сколько в плане безопасности. Добавим простое действие, которое удаляет объект из базы данных:
public ActionResult Delete(int id) { Book b = db.Books.Find(id); if (b != null) { db.Books.Remove(b); db.SaveChanges(); } return RedirectToAction("Index"); }
Вначале мы проверяем, а есть ли такой объект в бд, и если есть, то вызываем метод db.Books.Remove(b)
. Он установит статус объекта модели в Deleted
,
благодаря чему EntityFramework при вызове метода db.SaveChanges
сгенерирует sql-выражение DELETE. Но мы можем сами указать статус явным образом:
public ActionResult Delete(int id) { Book b = new Book { Id = id }; db.Entry(b).State = EntityState.Deleted; db.SaveChanges(); return RedirectToAction("Index"); }
Подобный подход имеет один плюс - мы избегаем первого запроса к бд, который у нас был в выражении Book b = db.Books.Find(id);
. То есть
вместо двух запросов к БД теперь у нас только один. Но в целом подобный метод на удаление имеет один минус в плане безопасности.
Допустим, нам пришло электронное письмо, в которое была внедрена картинка посредством тега:
<img src="http://адрес_нашего_сайта/Home/Delete/1" />
В итоге при открытии письма 1-я запись в таблице может быть удалена. Уязвимость касается не только писем, но может проявляться и в других местах, но смысл один - GET-запрос к методу Delete несет потенциальную уязвимость. Поэтому переделаем метод следующим образом:
[HttpGet] public ActionResult Delete(int id) { Book b = db.Books.Find(id); if (b == null) { return HttpNotFound(); } return View(b); } [HttpPost, ActionName("Delete")] public ActionResult DeleteConfirmed(int id) { Book b = db.Books.Find(id); if (b == null) { return HttpNotFound(); } db.Books.Remove(b); db.SaveChanges(); return RedirectToAction("Index"); }
Теперь вместо одного метода Delete целых два. Атрибут ActionName("Delete")
указывает, что метод DeleteConfirmed будет восприниматься
как действие Delete. Первый метод передает удаляемый объект в представление. На представлении с помощью нажатия кнопки мы сможем
подтвержить удаление. И удаляемый id уйдет второму методу по запросу POST. Таким образом, мы уйдем от уязвимости GET-запроса. Ну и само представление:
@{ Layout = "~/Views/Shared/_Layout.cshtml"; } @model BookStore.Models.Book <h2>Удаление книги</h2> <dl> <dt>Название</dt> <dd> @Html.DisplayFor(model => model.Name) </dd> <dt>Автор</dt> <dd> @Html.DisplayFor(model => model.Author) </dd> <dt>Цена</dt> <dd> @Html.DisplayFor(model => model.Price) </dd> </dl> @using (Html.BeginForm()) { <input type="submit" value="Удалить" /> }