Поделиться через


Знакомство с веб-страницы ASP.NET — обновление данных базы данных

; автор — Том ФитцМакен (Tom FitzMacken)

В этом руководстве показано, как обновить (изменить) существующую запись базы данных при использовании веб-страницы ASP.NET (Razor). Предполагается, что вы завершили серию до ввода данных с помощью форм с помощью веб-страницы ASP.NET.

Из этого руководства вы узнаете, как выполнять такие задачи:

  • Как выбрать отдельную запись во вспомогательном WebGrid элементе.
  • Чтение одной записи из базы данных.
  • Как предварительно загрузить форму со значениями из записи базы данных.
  • Обновление существующей записи в базе данных.
  • Как хранить информацию на странице без ее отображения.
  • Использование скрытого поля для хранения информации.

Обсуждаемые функции и технологии:

  • Помощник WebGrid .
  • Команда SQL Update .
  • метод Database.Execute ;
  • Скрытые поля (<input type="hidden">).

Что вы создадите

В предыдущем руководстве вы узнали, как добавить запись в базу данных. Здесь вы узнаете, как отобразить запись для редактирования. На странице Фильмы вы обновите вспомогательный WebGrid элемент таким образом, чтобы он отображал ссылку Изменить рядом с каждым фильмом:

Отображение WebGrid, включая ссылку

Щелкнув ссылку Изменить , вы перейдете на другую страницу, где сведения о фильме уже находятся в форме:

Страница

Вы можете изменить любое из значений. При отправке изменений код на странице обновляет базу данных и возвращается к списку фильмов.

Эта часть процесса работает почти так же, как страница AddMovie.cshtml , созданная в предыдущем руководстве, поэтому большая часть этого руководства будет знакома.

Существует несколько способов редактирования отдельного фильма. Показанный подход был выбран, так как его легко реализовать и понять.

Для начала обновите страницу Фильмы , чтобы каждый список фильмов также содержал ссылку Изменить .

Откройте файл Movies.cshtml .

В теле страницы измените разметку WebGrid , добавив столбец. Ниже приведена измененная разметка.

@grid.GetHtml(
    tableStyle: "grid",
    headerStyle: "head",
    alternatingRowStyle: "alt",
    columns: grid.Columns(
        grid.Column(format: @<a href="~/EditMovie?id=@item.ID">Edit</a>),
        grid.Column("Title"),
        grid.Column("Genre"),
        grid.Column("Year")
    )
)

Новый столбец следующий:

grid.Column(format: @<a href="~/EditMovie?id=@item.ID)">Edit</a>)

В этом столбце показана ссылка (<a> элемент), текст которой имеет надпись "Изменить". Мы создадим ссылку, которая выглядит следующим образом при запуске страницы со значением id , отличным для каждого фильма:

http://localhost:43097/EditMovie?id=7

Эта ссылка вызовет страницу с именем EditMovie и передаст строку ?id=7 запроса на нее.

Синтаксис нового столбца может выглядеть немного сложно, но это только потому, что он объединяет несколько элементов. Каждый отдельный элемент прост. Если сосредоточиться только на элементе, вы увидите <a> следующую разметку:

<a href="~/EditMovie?id=@item.ID)">Edit</a>

Некоторый фон работы сетки: сетка отображает строки, по одному для каждой записи базы данных, а также столбцы для каждого поля в записи базы данных. При создании каждой строки сетки item объект содержит запись базы данных (элемент) для этой строки. Такое расположение позволяет в коде получить данные для этой строки. Это то, что вы видите здесь: выражение item.ID получает значение идентификатора текущего элемента базы данных. Вы можете получить любое из значений базы данных (название, жанр или год) таким же образом с помощью item.Title, item.Genreили item.Year.

Выражение "~/EditMovie?id=@item.ID объединяет жестко закодированную часть целевого URL-адреса (~/EditMovie?id=) с этим динамически производным идентификатором. (Вы видели ~ оператор в предыдущем руководстве. Это оператор ASP.NET, представляющий текущий корень веб-сайта.)

В результате эта часть разметки в столбце просто создает нечто вроде следующей разметки во время выполнения:

href="/EditMovie?id=2"

Естественно, фактическое значение будет разным для каждой id строки.

Создание пользовательского отображения для столбца сетки

Теперь вернитесь к столбцу сетки. В трех столбцах, которые вы изначально имели в сетке, отображались только значения данных (название, жанр и год). Вы указали это отображение, передав имя столбца базы данных, например grid.Column("Title").

Новый столбец Изменить ссылку отличается. Вместо указания имени столбца передается format параметр . Этот параметр позволяет определить разметку, которая WebGrid будет отображаться вспомогательной службой вместе со item значением для отображения данных столбца в виде полужирного или зеленого цвета или в любом формате. Например, если вы хотите, чтобы заголовок выглядел полужирным, можно создать столбец, как в следующем примере:

grid.Column(format:@<strong>@item.Title</strong>)

(Различные @ символы, которые вы видите в свойстве, помечают format переход между разметкой и значением кода.)

Как только вы узнаете о свойстве format , проще понять, как создается новый столбец Изменить ссылку:

grid.Column(format: @<a href="~/EditMovie?id=@item.ID">Edit</a>),

Столбец состоит только из разметки, отображающей ссылку, а также некоторые сведения (идентификатор), извлеченные из записи базы данных для строки.

Совет

Именованные и позиционные параметры для метода

Часто при вызове метода и передаче ему параметров просто перечисляются значения параметров, разделенные запятыми. Вот несколько примеров.

db.Execute(insertCommand, title, genre, year)

Validation.RequireField("title", "You must enter a title")

Мы не упоминание проблему, когда вы впервые увидели этот код, но в каждом случае вы передаете параметры в методы в определенном порядке, а именно в порядке, в котором параметры определены в этом методе. Для db.Execute и Validation.RequireFields, если вы перепутали порядок передаваемых значений, вы получите сообщение об ошибке при запуске страницы или, по крайней мере, некоторые странные результаты. Очевидно, что необходимо знать порядок передачи параметров. (В WebMatrix IntelliSense может помочь вам узнать имя, тип и порядок параметров.)

В качестве альтернативы передаче значений по порядку можно использовать именованные параметры. (Передача параметров по порядку называется использованием позиционных параметров.) Для именованных параметров при передаче его значения явно указывается имя параметра. В этих руководствах вы уже несколько раз использовали именованные параметры. Пример:

var grid = new WebGrid(source: selectedData, defaultSort: "Genre", rowsPerPage:3)

и

@grid.GetHtml(
    tableStyle: "grid",
    headerStyle: "head",
    alternatingRowStyle: "alt",
    columns: grid.Columns(
       grid.Column("Title"),
       grid.Column("Genre"),
       grid.Column("Year")
    )
)

Именованные параметры удобно использовать в нескольких ситуациях, особенно если метод принимает много параметров. Во-первых, вы хотите передать только один или два параметра, но значения, которые вы хотите передать, не являются одними из первых позиций в списке параметров. Другая ситуация заключается в том, что вы хотите сделать код более удобочитаемым, передавая параметры в порядке, который имеет наибольшее значение.

Очевидно, что для использования именованных параметров необходимо знать имена параметров. WebMatrix IntelliSense может отображать имена, но в настоящее время они не могут быть заполнены.

Создание страницы редактирования

Теперь можно создать страницу EditMovie . Когда пользователи щелкают ссылку Изменить , они поймут на этой странице.

Создайте страницу с именем EditMovie.cshtml и замените содержимое файла следующей разметкой:

<!DOCTYPE html>
<html>
  <head>
   <meta charset="utf-8" />
   <title>Edit a Movie</title>
    <style>
      .validation-summary-errors{
        border:2px dashed red;
        color:red;
        font-weight:bold;
        margin:12px;
      }
    </style>
  </head>
  <body>
    <h1>Edit a Movie</h1>
    @Html.ValidationSummary()
    <form method="post">
      <fieldset>
        <legend>Movie Information</legend>

        <p><label for="title">Title:</label>
           <input type="text" name="title" value="@title" /></p>

        <p><label for="genre">Genre:</label>
           <input type="text" name="genre" value="@genre" /></p>

        <p><label for="year">Year:</label>
           <input type="text" name="year" value="@year" /></p>

        <input type="hidden" name="movieid" value="@movieId" />

        <p><input type="submit" name="buttonSubmit" value="Submit Changes" /></p>
      </fieldset>
    </form>
  </body>
</html>

Эта разметка и код похожи на те, что есть на странице AddMovie . В тексте кнопки отправки есть небольшая разница. Как и на странице AddMovie , существует Html.ValidationSummary вызов, который будет отображать ошибки проверки, если таковые имеются. На этот раз мы оставим вызовы к Validation.Message, так как ошибки будут отображаться в сводке проверки. Как отмечалось в предыдущем руководстве, можно использовать сводку проверки и отдельные сообщения об ошибках в различных сочетаниях.

Обратите внимание еще раз, что method атрибут <form> элемента имеет значение post. Как и на странице AddMovie.cshtml , эта страница вносит изменения в базу данных. Поэтому эта форма должна выполнять POST операцию. (Дополнительные сведения о различиях между GET операциями и POST см. в боковой панели GET, POST и HTTP Verb Safety в руководстве по HTML-формам.)

Как вы видели в предыдущем руководстве value , атрибуты текстовых полей задаются с помощью кода Razor для их предварительной загрузки. На этот раз, однако, вы используете переменные, такие как title и genre , для этой задачи, а не Request.Form["title"]:

<input type="text" name="title" value="@title" />

Как и раньше, эта разметка предварительно загружает значения текстового поля со значениями фильма. Через некоторое время вы увидите, почему на этот раз удобно использовать переменные вместо Request объекта .

На этой странице также есть <input type="hidden"> элемент . Этот элемент сохраняет идентификатор фильма, не делая его видимым на странице. Идентификатор изначально передается на страницу с помощью значения строки запроса (?id=7 или аналогичного в URL-адресе). Поместив значение идентификатора в скрытое поле, вы можете убедиться, что оно доступно при отправке формы, даже если у вас больше нет доступа к исходному URL-адресу, по которому была вызвана страница.

В отличие от страницы AddMovie , код для страницы EditMovie имеет две отдельные функции. Первая функция заключается в том, что при первом отображении страницы (и только затем) код получает идентификатор фильма из строки запроса. Затем код использует идентификатор для чтения соответствующего фильма из базы данных и его отображения (предварительной загрузки) в текстовых полях.

Вторая функция заключается в том, что, когда пользователь нажимает кнопку Отправить изменения , код должен считывать значения текстовых полей и проверять их. Код также должен обновить элемент базы данных новыми значениями. Этот метод аналогичен добавлению записи, как вы видели в AddMovie.

Добавление кода для чтения одного фильма

Чтобы выполнить первую функцию, добавьте следующий код в начало страницы:

@{
    var title = "";
    var genre = "";
    var year = "";
    var movieId = "";

    if(!IsPost){
        if(!Request.QueryString["ID"].IsEmpty()){
            movieId = Request.QueryString["ID"];
            var db = Database.Open("WebPagesMovies");
            var dbCommand = "SELECT * FROM Movies WHERE ID = @0";
            var row = db.QuerySingle(dbCommand, movieId);
            title = row.Title;
            genre = row.Genre;
            year = row.Year;
        }
        else{
            Validation.AddFormError("No movie was selected.");
        }
    }
}

Большая часть этого кода находится внутри блока, который запускает if(!IsPost). Оператор ! означает "нет", поэтому выражение означает, если этот запрос не является отправкой после отправки, что является косвенным способом сказать , является ли этот запрос первым запуском этой страницы. Как отмечалось ранее, этот код должен выполняться только при первом запуске страницы. Если вы не заключили код в if(!IsPost), он будет выполняться каждый раз при вызове страницы в первый раз или в ответ на нажатие кнопки.

Обратите внимание, что код на этот раз содержит else блок. Как мы уже говорили при вводе if блоков, иногда требуется выполнить альтернативный код, если условие, которое вы тестируете, не соответствует действительности. Вот так и есть. Если условие прошло (т. е. если идентификатор, переданный на страницу, в порядке), вы считываете строку из базы данных. Однако если условие не прошло, else блок запускается, а код задает сообщение об ошибке.

Проверка значения, переданного на страницу

Код использует Request.QueryString["id"] для получения идентификатора, передаваемого на страницу. Код гарантирует, что значение действительно передано для идентификатора. Если значение не было передано, код задает ошибку проверки.

В этом коде показан другой способ проверки информации. В предыдущем руководстве вы работали со вспомогательным помощником Validation . Вы зарегистрировали поля для проверки и ASP.NET автоматически выполнили проверку и отображали ошибки с помощью Html.ValidationMessage и Html.ValidationSummary. Однако в этом случае вы не выполняете проверку введенных пользователем данных. Вместо этого вы выполняете проверку значения, которое было передано на страницу из другого места. Помощник Validation не делает этого за вас.

Поэтому вы проверка значение самостоятельно, проверив его с if(!Request.QueryString["ID"].IsEmpty()помощью ). Если возникла проблема, вы можете отобразить ошибку с помощью Html.ValidationSummary, как и во вспомогательном средстве Validation . Для этого необходимо вызвать Validation.AddFormError и передать сообщение для отображения. Validation.AddFormError — это встроенный метод, который позволяет определять пользовательские сообщения, которые связываются с уже знакомой системой проверки. (Далее в этом руководстве мы поговорим о том, как сделать этот процесс проверки немного более надежным.)

Убедившись, что для фильма есть идентификатор, код считывает базу данных и ищет только один элемент базы данных. (Вы, вероятно, заметили общий шаблон для операций с базой данных: откройте базу данных, определите инструкцию SQL и выполните инструкцию.) На этот раз инструкция SQL Select включает в себя WHERE ID = @0. Так как идентификатор уникален, можно вернуть только одну запись.

Запрос выполняется с помощью db.QuerySingle (не db.Query, как для списка фильмов), и код помещает результат в переменную row . Имя row является произвольным. Переменным можно присвоить любое имя. Затем переменные, инициализированные вверху, заполняются сведениями о фильме, чтобы эти значения можно было отобразить в текстовых полях.

Тестирование страницы редактирования (пока)

Если вы хотите протестировать страницу, запустите страницу Фильмы и щелкните ссылку Изменить рядом с любым фильмом. Вы увидите страницу EditMovie с заполненными сведениями для выбранного фильма:

Снимок экрана: страница

Обратите внимание, что URL-адрес страницы содержит что-то вроде ?id=10 (или другое число). На данный момент вы проверили работу ссылок "Изменить " на странице "Фильм ", что страница считывает идентификатор из строки запроса и что запрос базы данных для получения одной записи фильма работает.

Вы можете изменить сведения о фильме, но при нажатии кнопки Отправить изменения ничего не происходит.

Добавление кода для обновления фильма с учетом изменений пользователя

Чтобы реализовать вторую функцию (сохранение изменений) в файле EditMovie.cshtml , добавьте следующий код непосредственно в закрывающую фигурную скобку @ блока. (Если вы не уверены, куда именно следует поместить код, вы можете просмотреть полный список кода для страницы Редактирование фильма , которая отображается в конце этого руководства.)

if(IsPost){
    Validation.RequireField("title", "You must enter a title");
    Validation.RequireField("genre", "Genre is required");
    Validation.RequireField("year", "You haven't entered a year");
    Validation.RequireField("movieid", "No movie ID was submitted!");

    title = Request.Form["title"];
    genre = Request.Form["genre"];
    year = Request.Form["year"];
    movieId = Request.Form["movieId"];

    if(Validation.IsValid()){
        var db = Database.Open("WebPagesMovies");
        var updateCommand = "UPDATE Movies SET Title=@0, Genre=@1, Year=@2 WHERE Id=@3";
        db.Execute(updateCommand, title, genre, year, movieId);
        Response.Redirect("~/Movies");
   }
}

Опять же, эта разметка и код похожи на код в AddMovie. Код находится в блоке if(IsPost) , так как этот код выполняется только тогда, когда пользователь нажимает кнопку Отправить изменения , то есть когда (и только когда) форма была опубликована. В этом случае вы не используете такой тест, как if(IsPost && Validation.IsValid()), то есть вы не объединяете оба теста с помощью И. На этой странице вы сначала определяете, есть ли отправка формы (if(IsPost)), и только затем регистрируете поля для проверки. Затем можно протестировать результаты проверки (if(Validation.IsValid()). Поток немного отличается от на странице AddMovie.cshtml , но результат будет таким же.

Значения текстовых полей можно получить с помощью Request.Form["title"] и аналогичного кода для других <input> элементов. Обратите внимание, что на этот раз код получает идентификатор фильма из скрытого поля (<input type="hidden">). При первом запуске страницы код получил идентификатор из строки запроса. Вы получите значение из скрытого поля, чтобы убедиться, что вы получаете идентификатор фильма, который был первоначально показан, на случай, если строка запроса была каким-то образом изменена с тех пор.

Действительно важное различие между кодом AddMovie и этим кодом заключается в том, что в этом коде используется инструкция SQL Update вместо Insert Into оператора . В следующем примере показан синтаксис инструкции SQL Update :

UPDATE table SET col1="value", col2="value", col3="value" ... WHERE ID = value

Вы можете указать любые столбцы в любом порядке, и вам не обязательно обновлять каждый столбец во время Update операции. (Вы не можете обновить сам идентификатор, так как это фактически сохранит запись как новую, и это не разрешено для Update операции.)

Примечание

Важно Предложение Where с идентификатором очень важно, так как именно так база данных знает, какую запись базы данных требуется обновить. Если вы отклолись от Where предложения , база данных обновит все записи в базе данных. В большинстве случаев это было бы катастрофой.

В коде обновляемые значения передаются в инструкцию SQL с помощью заполнителей. Чтобы повторить то, что мы уже говорили: в целях безопасности используйте только заполнители для передачи значений в инструкцию SQL.

После того как код использует db.Execute для выполнения инструкции Update , он перенаправляется обратно на страницу со списком, где можно увидеть изменения.

Совет

Разные инструкции SQL, разные методы

Возможно, вы заметили, что используете несколько разные методы для выполнения разных инструкций SQL. Чтобы выполнить Select запрос, который потенциально возвращает несколько записей, используйте Query метод . Чтобы выполнить Select запрос, который возвращает только один элемент базы данных, используйте QuerySingle метод . Чтобы выполнить команды, которые вносят изменения, но не возвращают элементы базы данных, используйте Execute метод .

У вас должны быть разные методы, так как каждый из них возвращает разные результаты, как вы уже видели в различиях между Query и QuerySingle. (Метод Execute фактически также возвращает значение, а именно количество строк базы данных, на которые повлияла команда, но вы игнорируете это до сих пор.)

Конечно, Query метод может возвращать только одну строку базы данных. Однако ASP.NET всегда обрабатывает результаты Query метода как коллекцию. Даже если метод возвращает только одну строку, ее необходимо извлечь из коллекции. Таким образом, в ситуациях, когда вы знаете , что вы получите только одну строку, это немного удобнее использовать QuerySingle.

Существует несколько других методов, которые выполняют определенные типы операций с базами данных. Список методов базы данных можно найти в кратком справочнике по API веб-страницы ASP.NET.

Обеспечение надежности проверки идентификатора

При первом запуске страницы вы получите идентификатор фильма из строки запроса, чтобы получить этот фильм из базы данных. Вы убедились, что на самом деле есть значение для поиска, что вы сделали с помощью этого кода:

if(!IsPost){
    if(!Request.QueryString["ID"].IsEmpty()){
        // Etc.
    }
}

Этот код использовался для того, чтобы убедиться, что если пользователь попадает на страницу EditMovies без предварительного выбора фильма на странице Фильмы , на странице отображается понятное сообщение об ошибке. (В противном случае пользователи увидят ошибку, которая, скорее всего, просто запутает их.)

Однако эта проверка не очень надежна. Страница также может вызываться со следующими ошибками:

  • Идентификатор не является числом. Например, страницу можно вызвать с помощью URL-адреса, например http://localhost:nnnnn/EditMovie?id=abc.
  • Идентификатор — это число, но он ссылается на фильм, который не существует (например, http://localhost:nnnnn/EditMovie?id=100934).

Если вам интересно увидеть ошибки, связанные с этими URL-адресами, запустите страницу Фильмы . Выберите фильм для редактирования, а затем измените URL-адрес страницы EditMovie на URL-адрес, содержащий алфавитный идентификатор или идентификатор несуществующего фильма.

Так что же делать? Первое исправление — убедиться, что на страницу передается не только идентификатор, но идентификатор является целым числом. Измените код для !IsPost теста, чтобы он выглядел следующим образом:

if(!IsPost){
    if(!Request.QueryString["ID"].IsEmpty() && Request.QueryString["ID"].IsInt()) {
       // Etc.

Вы добавили в тест второе условие, связанное IsEmpty с && (логическое И):

Request.QueryString["ID"].IsInt()

Возможно, вы помните из руководства По программированию в веб-страницы ASP.NET, что такие методы, как AsBoolAsInt символьная строка, преобразуются в какой-то другой тип данных. Методы IsInt (и другие, такие как IsBool и IsDateTime) похожи. Однако они проверяют только возможность преобразования строки без фактического выполнения преобразования. Поэтому здесь вы, по сути, говорите, может ли значение строки запроса быть преобразовано в целое число ....

Другая потенциальная проблема — поиск фильма, который не существует. Код для получения фильма выглядит следующим образом:

var row = db.QuerySingle(dbCommand, movieId);

Если передать movieId в метод значение QuerySingle , которое не соответствует фактическому фильму, ничего не возвращается, а следующие инструкции (например, title=row.Title) приводят к ошибкам.

Опять же, есть простое исправление. db.QuerySingle Если метод не возвращает результатов, row переменная будет иметь значение NULL. Таким образом, вы можете проверка, является ли row переменная null, прежде чем пытаться получить из нее значения. Следующий код добавляет if блок вокруг операторов, которые получают значения из row объекта :

if(row != null) {
    title = row.Title;
    genre = row.Genre;
    year = row.Year;
}
else{
    Validation.AddFormError("No movie was found for that ID.");
}

С помощью этих двух дополнительных проверочных тестов страница становится более маркерозащищенной. Полный код для ветви !IsPost теперь выглядит следующим образом:

if(!IsPost){
    if(!Request.QueryString["ID"].IsEmpty() && Request.QueryString["ID"].IsInt()) {
        movieId = Request.QueryString["ID"];
        var db = Database.Open("WebPagesMovies");
        var dbCommand = "SELECT * FROM Movies WHERE ID = @0";
        var row = db.QuerySingle(dbCommand, movieId);

        if(row != null) {
            title = row.Title;
            genre = row.Genre;
            year = row.Year;
        }
        else {
            Validation.AddFormError("No movie was found for that ID.");
        }
    }
    else {
        Validation.AddFormError("No movie was selected.");
    }
}

Еще раз заметим, что эта задача хорошо подходит для else блока. Если тесты не пройдены, блокируются else сообщения об ошибках.

Последнее и полезное описание — добавить ссылку обратно на страницу Фильмы . В обычном потоке событий пользователи начинают с страницы Фильмы и щелкают ссылку Изменить . Это приведет их на страницу EditMovie , где они могут редактировать фильм и нажать кнопку. После обработки изменения код перенаправляется обратно на страницу Фильмы .

Но:

  • Пользователь может решить ничего не изменять.
  • Пользователь мог перейти на эту страницу, не щелкнув ссылку Изменить на странице Фильмы .

В любом случае вы хотите, чтобы они легко вернулись к списку main. Это простое исправление: добавьте следующую разметку сразу после закрывающего </form> тега в разметке:

<p><a href="~/Movies">Return to movie listing</a></p>

Эта разметка использует тот же синтаксис для <a> элемента, который вы видели в других местах. URL-адрес означает ~ "корень веб-сайта".

Тестирование процесса обновления фильма

Теперь вы можете протестировать. Запустите страницу Фильмы и нажмите кнопку Изменить рядом с фильмом. Когда откроется страница EditMovie , внесите изменения в фильм и нажмите кнопку Отправить изменения. Когда появится список фильмов, убедитесь, что изменения отображаются.

Чтобы убедиться, что проверка работает, нажмите кнопку Изменить для другого фильма. Когда вы перейдите на страницу EditMovie , очистите поле "Жанр " (или поле "Год " или и то, и другое) и попробуйте отправить изменения. Вы увидите ошибку, как и следовало ожидать:

Страница

Щелкните ссылку Вернуться к списку фильмов , чтобы отменить изменения и вернуться на страницу Фильмы .

Ближайшие к следующему

В следующем руководстве вы узнаете, как удалить запись фильма.

@{
    var db = Database.Open("WebPagesMovies") ;
    var selectCommand = "SELECT * FROM Movies";
    var searchTerm = "";

    if(!Request.QueryString["searchGenre"].IsEmpty() ) {
        selectCommand = "SELECT * FROM Movies WHERE Genre = @0";
        searchTerm = Request.QueryString["searchGenre"];
    }

    if(!Request.QueryString["searchTitle"].IsEmpty() ) {
        selectCommand = "SELECT * FROM Movies WHERE Title LIKE @0";
        searchTerm = "%" + Request.QueryString["searchTitle"] + "%";
    }

    var selectedData = db.Query(selectCommand, searchTerm);
    var grid = new WebGrid(source: selectedData, defaultSort: "Genre", rowsPerPage:3);
}

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>Movies</title>
        <style type="text/css">
          .grid { margin: 4px; border-collapse: collapse; width: 600px; }
          .grid th, .grid td { border: 1px solid #C0C0C0; padding: 5px; }
          .head { background-color: #E8E8E8; font-weight: bold; color: #FFF; }
          .alt { background-color: #E8E8E8; color: #000; }
        </style>
    </head>
    <body>
        <h1>Movies</h1>
          <form method="get">
              <div>
                <label for="searchGenre">Genre to look for:</label>
                <input type="text" name="searchGenre" value="@Request.QueryString["searchGenre"]" />
                <input type="Submit" value="Search Genre" /><br/>
                (Leave blank to list all movies.)<br/>
                </div>

              <div>
                  <label for="SearchTitle">Movie title contains the following:</label>
                  <input type="text" name="searchTitle" value="@Request.QueryString["searchTitle"]" />
                  <input type="Submit" value="Search Title" /><br/>
                </div>
            </form>

        <div>
             @grid.GetHtml(
                tableStyle: "grid",
                headerStyle: "head",
                alternatingRowStyle: "alt",
                columns: grid.Columns(
                    grid.Column(format: @<a href="~/EditMovie?id=@item.ID">Edit</a>),
                    grid.Column("Title"),
                    grid.Column("Genre"),
                    grid.Column("Year")
                )
            )
        </div>
    <p>
        <a href="~/AddMovie">Add a movie</a>
    </p>
    </body>
</html>

Заполнение списка страниц для редактирования страницы фильма

@{
    var title = "";
    var genre = "";
    var year = "";
    var movieId = "";

    if(!IsPost){
        if(!Request.QueryString["ID"].IsEmpty() && Request.QueryString["ID"].IsInt()) {
            movieId = Request.QueryString["ID"];
            var db = Database.Open("WebPagesMovies");
            var dbCommand = "SELECT * FROM Movies WHERE ID = @0";
            var row = db.QuerySingle(dbCommand, movieId);

            if(row != null) {
                title = row.Title;
                genre = row.Genre;
                year = row.Year;
            }
            else{
                Validation.AddFormError("No movie was selected.");
            }
        }
        else{
            Validation.AddFormError("No movie was selected.");
        }
    }

    if(IsPost){
        Validation.RequireField("title", "You must enter a title");
        Validation.RequireField("genre", "Genre is required");
        Validation.RequireField("year", "You haven't entered a year");
        Validation.RequireField("movieid", "No movie ID was submitted!");

        title = Request.Form["title"];
        genre = Request.Form["genre"];
        year = Request.Form["year"];
        movieId = Request.Form["movieId"];

        if(Validation.IsValid()){
            var db = Database.Open("WebPagesMovies");
            var updateCommand = "UPDATE Movies SET Title=@0, Genre=@1, Year=@2 WHERE Id=@3";
            db.Execute(updateCommand, title, genre, year, movieId);
            Response.Redirect("~/Movies");
        }
    }
}

<!DOCTYPE html>
<html>
  <head>
   <meta charset="utf-8" />
   <title>Edit a Movie</title>
    <style>
      .validation-summary-errors{
        border:2px dashed red;
        color:red;
        font-weight:bold;
        margin:12px;
      }
    </style>
  </head>
  <body>
    <h1>Edit a Movie</h1>
      @Html.ValidationSummary()
      <form method="post">
      <fieldset>
        <legend>Movie Information</legend>

        <p><label for="title">Title:</label>
           <input type="text" name="title" value="@title" /></p>

        <p><label for="genre">Genre:</label>
           <input type="text" name="genre" value="@genre" /></p>

        <p><label for="year">Year:</label>
           <input type="text" name="year" value="@year" /></p>

        <input type="hidden" name="movieid" value="@movieId" />

        <p><input type="submit" name="buttonSubmit" value="Submit Changes" /></p>
      </fieldset>
    </form>
    <p><a href="~/Movies">Return to movie listing</a></p>
  </body>
</html>

Дополнительные ресурсы