Добавление и удаление данных

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 31.10.2015

Добавление данных

В предыдущей теме мы посмотрели, как редактировать данные. Продолжим работу с моделью 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="Удалить"  />
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850