Поиск
Примечание
Обновленная версия этого руководства доступна здесь с использованием последней версии Visual Studio. В новом руководстве используется ASP.NET Core MVC, который предоставляет множество улучшений по сравнению с этим руководством.
В этом руководстве описывается модель MVC ASP.NET Core с контроллерами и представлениями. Razor Pages — это новая альтернатива в ASP.NET Core, страничной модели программирования, которая упрощает и повышает эффективность создания пользовательского веб-интерфейса. Мы рекомендуем ознакомиться с руководством по Razor Pages до версии MVC. Руководство по Razor Pages:
- проще для выполнения;
- охватывает дополнительные возможности;
- Является предпочтительным подходом для разработки новых приложений.
Добавление метода поиска и представления поиска
В этом разделе вы добавите в метод действия возможность Index
поиска, которая позволяет искать фильмы по жанру или имени.
Предварительные требования
Чтобы сопоставить снимки экрана этого раздела, необходимо запустить приложение (F5) и добавить в базу данных следующие фильмы.
Заголовок | Дата выпуска | Genre | Цена |
---|---|---|---|
Охотники за привидениями | 6/8/1984 | Комедия | 6,99 |
Охотники за привидениями II | 6/16/1989 | Комедия | 6,99 |
Планета обезьян | 3/27/1986 | Действие | 5,99 |
Обновление формы индекса
Начните с обновления Index
метода action до существующего MoviesController
класса. Вот этот код:
public ActionResult Index(string searchString)
{
var movies = from m in db.Movies
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
return View(movies);
}
В первой строке Index
метода создается следующий запрос LINQ для выбора фильмов:
var movies = from m in db.Movies
select m;
Запрос определен на этом этапе, но еще не был выполнен в базе данных.
searchString
Если параметр содержит строку, запрос movies изменяется для фильтрации по значению строки поиска с использованием следующего кода:
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
Приведенный выше код s => s.Title
представляет собой лямбда-выражение. Лямбда-выражения используются в запросах LINQ на основе методов в качестве аргументов для стандартных методов операторов запросов, таких как метод Where , используемый в приведенном выше коде. Запросы LINQ не выполняются при их определении или изменении путем вызова метода, Where
например или OrderBy
. Вместо этого выполнение запроса откладывается, что означает, что вычисление выражения откладывается до фактического перебора его реализованного значения или ToList
вызова метода. Search
В примере запрос выполняется в представлении Index.cshtml. Дополнительные сведения об отложенном и немедленном выполнении запросов см. в разделе Выполнение запроса.
Примечание
Метод Contains выполняется в базе данных, а не в приведенном выше коде c#. В базе данных содержит сопоставляется с SQL LIKE, что не учитывает регистр.
Теперь можно обновить Index
представление, в котором будет отображаться форма для пользователя.
Запустите приложение и перейдите в папку /Movies/Index. Добавьте в URL-адрес строку запроса, например ?searchString=ghost
. Отображаются отфильтрованные фильмы.
Если изменить сигнатуру Index
метода на параметр с именем id
, id
параметр будет соответствовать {id}
заполнителю маршрутов по умолчанию, заданным в файле App_Start\RouteConfig.cs .
{controller}/{action}/{id}
Исходный Index
метод выглядит следующим образом:
public ActionResult Index(string searchString)
{
var movies = from m in db.Movies
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
return View(movies);
}
Измененный Index
метод будет выглядеть следующим образом:
public ActionResult Index(string id)
{
string searchString = id;
var movies = from m in db.Movies
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
return View(movies);
}
Теперь можно передать заголовок поиска в качестве данных маршрута (сегмент URL-адреса) вместо значения строки запроса.
Тем не менее пользователи вряд ли будут каждый раз изменять URL-адрес для поиска фильмов. Итак, теперь вам необходимо добавить пользовательский интерфейс для удобства фильтрации фильмов. Если вы изменили сигнатуру Index
метода, чтобы проверить, как передать параметр идентификатора с привязкой к маршруту, измените его так, чтобы Index
метод принимает строковый параметр с именем searchString
:
public ActionResult Index(string searchString)
{
var movies = from m in db.Movies
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
return View(movies);
}
Откройте файл Views\Movies\Index.cshtml и сразу после @Html.ActionLink("Create New", "Create")
добавьте разметку формы, выделенную ниже:
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
@using (Html.BeginForm()){
<p> Title: @Html.TextBox("SearchString") <br />
<input type="submit" value="Filter" /></p>
}
</p>
Вспомогательный Html.BeginForm
элемент создает открывающий <form>
тег. Вспомогающая Html.BeginForm
функция отправляет форму в себя, когда пользователь отправляет форму, нажимая кнопку Фильтр .
Visual Studio 2013 имеет хорошие улучшения при отображении и редактировании файлов представления. При запуске приложения с открытым файлом представления Visual Studio 2013 вызывает правильный метод действия контроллера для отображения представления.
Открыв представление индексов в Visual Studio (как показано на рисунке выше), коснитесь Ctr F5 или F5, чтобы запустить приложение, а затем попробуйте найти фильм.
Перегрузка метода отсутствует HttpPost
Index
. Он не нужен, так как метод не изменяет состояние приложения, а просто фильтрует данные.
Можно добавить следующий метод HttpPost Index
. В этом случае вызов действия будет соответствовать методу HttpPost Index
HttpPost Index
, и метод будет выполняться, как показано на рисунке ниже.
[HttpPost]
public string Index(FormCollection fc, string searchString)
{
return "<h3> From [HttpPost]Index: " + searchString + "</h3>";
}
Тем не менее при добавлении этой версии HttpPost
метода Index
существует ограничение на общую реализацию. Допустим, вам необходимо добавить в закладки конкретный поиск или отправить друзьям ссылку, по которой они могут просмотреть аналогичный отфильтрованный список фильмов. Обратите внимание, что URL-адрес HTTP-запроса POST совпадает с URL-адресом запроса GET (localhost:xxxxx/Movies/Index) — в самом URL-адресе нет сведений о поиске. Сейчас сведения о строке поиска отправляются на сервер в виде значения поля формы. Это означает, что вы не можете записать данные поиска для закладки или отправить друзьям в URL-адресе.
Решение заключается в использовании перегрузки BeginForm
, которая указывает, что запрос POST должен добавить сведения о поиске в URL-адрес и что они должны быть перенаправлены в HttpGet
версию Index
метода . Замените существующий метод без BeginForm
параметров следующей разметкой:
@using (Html.BeginForm("Index","Movies",FormMethod.Get))
Теперь при отправке поиска URL-адрес содержит строку поискового запроса. Поиск также переносится в метод HttpGet Index
, даже если у вас определен метод HttpPost Index
.
Добавление поиска по жанру
Если вы добавили HttpPost
версию Index
метода, удалите ее сейчас.
Затем вы добавите функцию, которая позволит пользователям искать фильмы по жанру. Замените метод Index
следующим кодом:
public ActionResult Index(string movieGenre, string searchString)
{
var GenreLst = new List<string>();
var GenreQry = from d in db.Movies
orderby d.Genre
select d.Genre;
GenreLst.AddRange(GenreQry.Distinct());
ViewBag.movieGenre = new SelectList(GenreLst);
var movies = from m in db.Movies
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
if (!string.IsNullOrEmpty(movieGenre))
{
movies = movies.Where(x => x.Genre == movieGenre);
}
return View(movies);
}
Эта версия Index
метода принимает дополнительный параметр, а именно movieGenre
. Первые несколько строк кода создают List
объект для хранения жанров фильмов из базы данных.
Следующий код определяет запрос LINQ, который извлекает все жанры из базы данных.
var GenreQry = from d in db.Movies
orderby d.Genre
select d.Genre;
Код использует AddRange
метод универсальной List
коллекции для добавления всех различных жанров в список. (Без модификатора Distinct
будут добавлены повторяющиеся жанры— например, комедия будет добавлена дважды в нашем примере). Затем код сохраняет список жанров в объекте ViewBag.MovieGenre
. Хранение данных категории (такие жанры фильмов) как объект SelectList в ViewBag
, а затем доступ к данным категории в раскрывающемся списке является типичным подходом для приложений MVC.
В следующем коде показано, как проверка параметр .movieGenre
Если он не пуст, код дополнительно ограничивает запрос фильмов, чтобы ограничить выбранные фильмы указанным жанром.
if (!string.IsNullOrEmpty(movieGenre))
{
movies = movies.Where(x => x.Genre == movieGenre);
}
Как было сказано ранее, запрос не выполняется в базе данных до тех пор, пока не будет выполнена итерация списка фильмов (что происходит в представлении после Index
возврата метода действия).
Добавление разметки в представление индекса для поддержки поиска по жанрам
Добавьте вспомогателя Html.DropDownList
в файл Views\Movies\Index.cshtml непосредственно перед вспомогательным TextBox
. Завершенная разметка показана ниже:
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
@using (Html.BeginForm("Index", "Movies", FormMethod.Get))
{
<p>
Genre: @Html.DropDownList("movieGenre", "All")
Title: @Html.TextBox("SearchString")
<input type="submit" value="Filter" />
</p>
}
</p>
<table class="table">
В приведенном ниже коде выполняется следующее:
@Html.DropDownList("movieGenre", "All")
Параметр MovieGenre предоставляет ключ для вспомогательного DropDownList
средства поиска IEnumerable<SelectListItem>
в ViewBag
. Объект ViewBag
был заполнен в методе действия:
public ActionResult Index(string movieGenre, string searchString)
{
var GenreLst = new List<string>();
var GenreQry = from d in db.Movies
orderby d.Genre
select d.Genre;
GenreLst.AddRange(GenreQry.Distinct());
ViewBag.movieGenre = new SelectList(GenreLst);
var movies = from m in db.Movies
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
if (!string.IsNullOrEmpty(movieGenre))
{
movies = movies.Where(x => x.Genre == movieGenre);
}
return View(movies);
}
Параметр All предоставляет метку параметра. Если проверить этот вариант в браузере, вы увидите, что его атрибут value пуст. Так как наш контроллер фильтрует if
только строку не является или пустой null
, отправка пустого значения для movieGenre
показывает все жанры.
Вы также можете задать параметр, который будет выбран по умолчанию. Если вы хотите использовать comedy в качестве параметра по умолчанию, измените код в контроллере следующим образом:
ViewBag.movieGenre = new SelectList(GenreLst, "Comedy");
Запустите приложение и перейдите по папке /Movies/Index. Попробуйте выполнить поиск по жанру, по имени фильма и по обоим критериям.
В этом разделе вы создали метод действия поиска и представление, которые позволяют пользователям выполнять поиск по названию и жанру фильма. В следующем разделе вы узнаете, как добавить свойство в Movie
модель и как добавить инициализатор, который автоматически создаст тестовую базу данных.