Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete ve verzi .NET 10 tohoto článku.
Upozorňující
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Autor: Rick Anderson
V této části přidáte funkci vyhledávání do Index metody akce, která umožňuje hledat filmy podle žánru nebo názvu.
Aktualizujte metodu Index nalezenou v Controllers/MoviesController.cs následujícím kódu:
public async Task<IActionResult> Index(string searchString)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
return View(await movies.ToListAsync());
}
Následující řádek v Index metodě akce vytvoří dotaz LINQ pro výběr filmů:
var movies = from m in _context.Movie
select m;
Dotaz je definován pouze v tomto okamžiku, nebyl spuštěn proti databázi.
searchString Pokud parametr obsahuje řetězec, dotaz filmy se upraví tak, aby filtrovaly hodnotu hledaného řetězce:
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
Výše s => s.Title!.ToUpper().Contains(searchString.ToUpper()) uvedený kód je výraz lambda. Lambda se používají v dotazech LINQ založených na Dotazy LINQ se nespouštějí, když jsou definovány nebo když jsou upraveny voláním metody, jako Whereje , Containsnebo OrderBy. Místo toho se odloží provádění dotazu. To znamená, že vyhodnocení výrazu je zpožděné, dokud se jeho dosažená hodnota ve skutečnosti iterated over nebo ToListAsync metoda volá. Další informace o odložené spuštění dotazu naleznete v tématu Provádění dotazů.
Poznámka:
Metoda Contains se spouští v databázi, ne v kódu jazyka C#. Citlivost případu na dotazu závisí na databázi a kolaci. Na SQL Serveru Contains se mapuje na SQL LIKE, což je nerozlišující velká a malá písmena. SQLite s výchozí kolací je kombinace rozlišování velkých a malých a velkých písmen v závislosti na dotazu. Informace o rozlišování dotazů SQLite pro případ najdete v následujících tématech:
Přejděte na /Movies/Index. Připojte řetězec dotazu, například ?searchString=Ghost k adrese URL. Zobrazí se filtrované filmy.
Pokud změníte podpis Index metody tak, aby měl název idparametr , id bude parametr odpovídat volitelnému {id} zástupného symbolu pro výchozí trasy nastavené v Program.cs.
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Změňte parametr na id a změňte všechny výskyty searchString na id.
Výše uvedená metoda Index:
public async Task<IActionResult> Index(string searchString)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
return View(await movies.ToListAsync());
}
Aktualizovaná Index metoda s parametrem id :
public async Task<IActionResult> Index(string id)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(id))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(id.ToUpper()));
}
return View(await movies.ToListAsync());
}
Název hledání teď můžete předat jako směrovací data (segment adresy URL) místo jako hodnotu řetězce dotazu.
Nemůžete ale očekávat, že uživatelé upraví adresu URL pokaždé, když chtějí hledat film. Teď tedy přidáte prvky uživatelského rozhraní, které jim pomůžou filtrovat filmy. Pokud jste změnili podpis Index metody tak, aby testoval, jak předat parametr vázaný ID na trasu, změňte ho zpět tak, aby přebírá parametr s názvem searchString:
public async Task<IActionResult> Index(string searchString)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
return View(await movies.ToListAsync());
}
Views/Movies/Index.cshtml Otevřete soubor a přidejte níže zvýrazněnou <form> značku:
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index">
<p>
<label>Title: <input type="text" name="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
Značka HTML <form> používá pomocníka značky formuláře, takže při odeslání formuláře se řetězec filtru odešle do Index akce kontroleru filmů. Uložte změny a pak filtr otestujte.
Neexistuje žádné [HttpPost] přetížení Index metody, jak byste mohli očekávat. Nepotřebujete ji, protože metoda nemění stav aplikace, jenom filtrování dat.
Můžete přidat následující [HttpPost] Index metodu.
[HttpPost]
public string Index(string searchString, bool notUsed)
{
return "From [HttpPost]Index: filter on " + searchString;
}
Parametr notUsed se používá k vytvoření přetížení pro metodu Index . O tom budeme mluvit později v tomto kurzu.
Pokud přidáte tuto metodu, vyvolání akce by odpovídalo [HttpPost] Index metodě a [HttpPost] Index metoda by se spustila, jak je znázorněno na obrázku níže.
I když ale přidáte tuto [HttpPost] verzi Index metody, existuje omezení způsobu implementace. Představte si, že chcete vytvořit záložku určitého hledání nebo chcete poslat odkaz přátelům, na které můžou kliknout, aby se zobrazil stejný filtrovaný seznam filmů. Všimněte si, že adresa URL požadavku HTTP POST je stejná jako adresa URL požadavku GET (localhost:{PORT}/Movies/Index) – v adrese URL nejsou žádné informace o hledání. Informace o vyhledávacím řetězci se odešlou na server jako hodnota pole formuláře. To můžete ověřit pomocí prohlížeče Vývojářské nástroje nebo vynikajícího nástroje Fiddler.
Následující obrázek ukazuje prohlížeč Chrome Vývojářské nástroje s vybranými kartami Síť a Záhlaví:
Karty Síť a datová část jsou vybrány pro zobrazení dat formuláře:
V textu požadavku můžete vidět hledaný parametr a token XSRF . Všimněte si, jak je uvedeno v předchozím kurzu, pomocník značky formuláře vygeneruje antiforgery token XSRF . Neupravujeme data, takže token v metodě kontroleru nemusíme ověřovat.
Vzhledem k tomu, že parametr vyhledávání je v textu požadavku, a ne v adrese URL, nemůžete zachytit tyto informace hledání, které chcete uložit do záložek nebo sdílet s ostatními. Opravte to zadáním požadavku HTTP GET na form značku, která se nachází v Views/Movies/Index.cshtml souboru.
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index" method="get">
<p>
<label>Title: <input type="text" name="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
Když teď odešlete hledání, adresa URL obsahuje řetězec vyhledávacího dotazu. Hledání také přejde na metodu HttpGet Index akce, i když máte metodu HttpPost Index .
Přidat hledání podle žánru
Do složky Models přidejte následující MovieGenreViewModel třídu:
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;
namespace MvcMovie.Models;
public class MovieGenreViewModel
{
public List<Movie>? Movies { get; set; }
public SelectList? Genres { get; set; }
public string? MovieGenre { get; set; }
public string? SearchString { get; set; }
}
Model zobrazení filmového žánru bude obsahovat:
- Seznam filmů.
- A
SelectListobsahující seznam žánrů. Uživatel tak může ze seznamu vybrat žánr. -
MovieGenre, který obsahuje vybraný žánr. -
SearchString, který obsahuje text, který uživatel zadá do vyhledávacího textového pole.
Nahraďte metodu IndexMoviesController.cs následujícím kódem:
// GET: Movies
public async Task<IActionResult> Index(string movieGenre, string searchString)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
var movies = from m in _context.Movie
select m;
if (!string.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
if (!string.IsNullOrEmpty(movieGenre))
{
movies = movies.Where(x => x.Genre == movieGenre);
}
var movieGenreVM = new MovieGenreViewModel
{
Genres = new SelectList(await genreQuery.Distinct().ToListAsync()),
Movies = await movies.ToListAsync()
};
return View(movieGenreVM);
}
Následující kód je LINQ dotaz, který načte všechny žánry z databáze.
// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
Žánry SelectList se vytvářejí tak, že promítnou různé žánry (nechceme, aby náš výběrový seznam měl duplicitní žánry).
Když uživatel vyhledá položku, hodnota hledání se zachovají do vyhledávacího pole.
Přidání vyhledávání podle žánru do zobrazení indexu
Aktualizace Index.cshtml nalezená v zobrazeních/filmy/ následujícím způsobem:
@model MvcMovie.Models.MovieGenreViewModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index" method="get">
<p>
<select asp-for="MovieGenre" asp-items="Model.Genres">
<option value="">All</option>
</select>
<label>Title: <input type="text" asp-for="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movies![0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies![0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies![0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies![0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movies!)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Prozkoumejte výraz lambda použitý v následujícím pomocníkovi HTML:
@Html.DisplayNameFor(model => model.Movies![0].Title)
V předchozím kódu DisplayNameFor pomocník HTML zkontroluje Title vlastnost odkazovanou ve výrazu lambda, aby určil zobrazovaný název. Vzhledem k tomu, že výraz lambda se kontroluje místo vyhodnocení, neobdržíte porušení přístupu, pokud model, model.Moviesnebo jsou nebo jsou nebo model.Movies[0] jsou null prázdné. Při vyhodnocování výrazu lambda (například @Html.DisplayFor(modelItem => item.Title)) se vyhodnocují hodnoty vlastností modelu. Následující ! je model.Movies null-forgiving, který se používá k deklaraci, že není null.Movies
Otestujte aplikaci vyhledáváním podle žánru, podle názvu filmu a obojího:
V této části přidáte funkci vyhledávání do Index metody akce, která umožňuje hledat filmy podle žánru nebo názvu.
Aktualizujte metodu Index nalezenou v Controllers/MoviesController.cs následujícím kódu:
public async Task<IActionResult> Index(string searchString)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
return View(await movies.ToListAsync());
}
Následující řádek v Index metodě akce vytvoří dotaz LINQ pro výběr filmů:
var movies = from m in _context.Movie
select m;
Dotaz je definován pouze v tomto okamžiku, nebyl spuštěn proti databázi.
searchString Pokud parametr obsahuje řetězec, dotaz filmy se upraví tak, aby filtrovaly hodnotu hledaného řetězce:
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
Výše s => s.Title!.ToUpper().Contains(searchString.ToUpper()) uvedený kód je výraz lambda. Lambda se používají v dotazech LINQ založených na Dotazy LINQ se nespouštějí, když jsou definovány nebo když jsou upraveny voláním metody, jako Whereje , Containsnebo OrderBy. Místo toho se odloží provádění dotazu. To znamená, že vyhodnocení výrazu je zpožděné, dokud se jeho dosažená hodnota ve skutečnosti iterated over nebo ToListAsync metoda volá. Další informace o odložené spuštění dotazu naleznete v tématu Provádění dotazů.
Poznámka:
Metoda Contains se spouští v databázi, ne v kódu jazyka C#. Citlivost případu na dotazu závisí na databázi a kolaci. Na SQL Serveru Contains se mapuje na SQL LIKE, což je nerozlišující velká a malá písmena. SQLite s výchozí kolací je kombinace rozlišování velkých a malých a velkých písmen v závislosti na dotazu. Informace o rozlišování dotazů SQLite pro případ najdete v následujících tématech:
Přejděte na /Movies/Index. Připojte řetězec dotazu, například ?searchString=Ghost k adrese URL. Zobrazí se filtrované filmy.
Pokud změníte podpis Index metody tak, aby měl název idparametr , id bude parametr odpovídat volitelnému {id} zástupného symbolu pro výchozí trasy nastavené v Program.cs.
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Změňte parametr na id a změňte všechny výskyty searchString na id.
Výše uvedená metoda Index:
public async Task<IActionResult> Index(string searchString)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
return View(await movies.ToListAsync());
}
Aktualizovaná Index metoda s parametrem id :
public async Task<IActionResult> Index(string id)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(id))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(id.ToUpper()));
}
return View(await movies.ToListAsync());
}
Název hledání teď můžete předat jako směrovací data (segment adresy URL) místo jako hodnotu řetězce dotazu.
Nemůžete ale očekávat, že uživatelé upraví adresu URL pokaždé, když chtějí hledat film. Teď tedy přidáte prvky uživatelského rozhraní, které jim pomůžou filtrovat filmy. Pokud jste změnili podpis Index metody tak, aby testoval, jak předat parametr vázaný ID na trasu, změňte ho zpět tak, aby přebírá parametr s názvem searchString:
public async Task<IActionResult> Index(string searchString)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
return View(await movies.ToListAsync());
}
Views/Movies/Index.cshtml Otevřete soubor a přidejte níže zvýrazněnou <form> značku:
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index">
<p>
<label>Title: <input type="text" name="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
Značka HTML <form> používá pomocníka značky formuláře, takže při odeslání formuláře se řetězec filtru odešle do Index akce kontroleru filmů. Uložte změny a pak filtr otestujte.
Neexistuje žádné [HttpPost] přetížení Index metody, jak byste mohli očekávat. Nepotřebujete ji, protože metoda nemění stav aplikace, jenom filtrování dat.
Můžete přidat následující [HttpPost] Index metodu.
[HttpPost]
public string Index(string searchString, bool notUsed)
{
return "From [HttpPost]Index: filter on " + searchString;
}
Parametr notUsed se používá k vytvoření přetížení pro metodu Index . O tom budeme mluvit později v tomto kurzu.
Pokud přidáte tuto metodu, vyvolání akce by odpovídalo [HttpPost] Index metodě a [HttpPost] Index metoda by se spustila, jak je znázorněno na obrázku níže.
I když ale přidáte tuto [HttpPost] verzi Index metody, existuje omezení způsobu implementace. Představte si, že chcete vytvořit záložku určitého hledání nebo chcete poslat odkaz přátelům, na které můžou kliknout, aby se zobrazil stejný filtrovaný seznam filmů. Všimněte si, že adresa URL požadavku HTTP POST je stejná jako adresa URL požadavku GET (localhost:{PORT}/Movies/Index) – v adrese URL nejsou žádné informace o hledání. Informace o vyhledávacím řetězci se odešlou na server jako hodnota pole formuláře. To můžete ověřit pomocí prohlížeče Vývojářské nástroje nebo vynikajícího nástroje Fiddler. Následující obrázek ukazuje prohlížeč Chrome Vývojářské nástroje:
V textu požadavku můžete vidět hledaný parametr a token XSRF . Všimněte si, jak je uvedeno v předchozím kurzu, pomocník značky formuláře vygeneruje antiforgery token XSRF . Neupravujeme data, takže token v metodě kontroleru nemusíme ověřovat.
Vzhledem k tomu, že parametr vyhledávání je v textu požadavku, a ne v adrese URL, nemůžete zachytit tyto informace hledání, které chcete uložit do záložek nebo sdílet s ostatními. Opravte to tak, že v souboru zadáte požadavek HTTP GETViews/Movies/Index.cshtml .
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index" method="get">
<p>
<label>Title: <input type="text" name="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
Když teď odešlete hledání, adresa URL obsahuje řetězec vyhledávacího dotazu. Hledání také přejde na metodu HttpGet Index akce, i když máte metodu HttpPost Index .
Následující kód ukazuje změnu značky form :
<form asp-controller="Movies" asp-action="Index" method="get">
Přidat hledání podle žánru
Do složky Models přidejte následující MovieGenreViewModel třídu:
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;
namespace MvcMovie.Models;
public class MovieGenreViewModel
{
public List<Movie>? Movies { get; set; }
public SelectList? Genres { get; set; }
public string? MovieGenre { get; set; }
public string? SearchString { get; set; }
}
Model zobrazení filmového žánru bude obsahovat:
- Seznam filmů.
- A
SelectListobsahující seznam žánrů. Uživatel tak může ze seznamu vybrat žánr. -
MovieGenre, který obsahuje vybraný žánr. -
SearchString, který obsahuje text, který uživatel zadá do vyhledávacího textového pole.
Nahraďte metodu IndexMoviesController.cs následujícím kódem:
// GET: Movies
public async Task<IActionResult> Index(string movieGenre, string searchString)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
var movies = from m in _context.Movie
select m;
if (!string.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
if (!string.IsNullOrEmpty(movieGenre))
{
movies = movies.Where(x => x.Genre == movieGenre);
}
var movieGenreVM = new MovieGenreViewModel
{
Genres = new SelectList(await genreQuery.Distinct().ToListAsync()),
Movies = await movies.ToListAsync()
};
return View(movieGenreVM);
}
Následující kód je LINQ dotaz, který načte všechny žánry z databáze.
// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
Žánry SelectList se vytvářejí tak, že promítnou různé žánry (nechceme, aby náš výběrový seznam měl duplicitní žánry).
Když uživatel vyhledá položku, hodnota hledání se zachovají do vyhledávacího pole.
Přidání vyhledávání podle žánru do zobrazení indexu
Aktualizace Index.cshtml nalezená v zobrazeních/filmy/ následujícím způsobem:
@model MvcMovie.Models.MovieGenreViewModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index" method="get">
<p>
<select asp-for="MovieGenre" asp-items="Model.Genres">
<option value="">All</option>
</select>
<label>Title: <input type="text" asp-for="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movies![0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies![0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies![0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies![0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movies!)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Prozkoumejte výraz lambda použitý v následujícím pomocníkovi HTML:
@Html.DisplayNameFor(model => model.Movies![0].Title)
V předchozím kódu DisplayNameFor pomocník HTML zkontroluje Title vlastnost odkazovanou ve výrazu lambda, aby určil zobrazovaný název. Vzhledem k tomu, že výraz lambda se kontroluje místo vyhodnocení, neobdržíte porušení přístupu, pokud model, model.Moviesnebo jsou nebo jsou nebo model.Movies[0] jsou null prázdné. Při vyhodnocování výrazu lambda (například @Html.DisplayFor(modelItem => item.Title)) se vyhodnocují hodnoty vlastností modelu. Následující ! je model.Movies null-forgiving, který se používá k deklaraci, že není null.Movies
Otestujte aplikaci vyhledáváním podle žánru, podle názvu filmu a obojího:
V této části přidáte funkci vyhledávání do Index metody akce, která umožňuje hledat filmy podle žánru nebo názvu.
Aktualizujte metodu Index nalezenou v Controllers/MoviesController.cs následujícím kódu:
public async Task<IActionResult> Index(string searchString)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
return View(await movies.ToListAsync());
}
Následující řádek v Index metodě akce vytvoří dotaz LINQ pro výběr filmů:
var movies = from m in _context.Movie
select m;
Dotaz je definován pouze v tomto okamžiku, nebyl spuštěn proti databázi.
searchString Pokud parametr obsahuje řetězec, dotaz filmy se upraví tak, aby filtrovaly hodnotu hledaného řetězce:
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
Výše s => s.Title!.ToUpper().Contains(searchString.ToUpper()) uvedený kód je výraz lambda. Lambda se používají v dotazech LINQ založených na Dotazy LINQ se nespouštějí, když jsou definovány nebo když jsou upraveny voláním metody, jako Whereje , Containsnebo OrderBy. Místo toho se odloží provádění dotazu. To znamená, že vyhodnocení výrazu je zpožděné, dokud se jeho dosažená hodnota ve skutečnosti iterated over nebo ToListAsync metoda volá. Další informace o odložené spuštění dotazu naleznete v tématu Provádění dotazů.
Poznámka:
Metoda Contains se spouští v databázi, ne v kódu jazyka C#. Citlivost případu na dotazu závisí na databázi a kolaci. Na SQL Serveru Contains se mapuje na SQL LIKE, což je nerozlišující velká a malá písmena. SQLite s výchozí kolací je kombinace rozlišování velkých a malých a velkých písmen v závislosti na dotazu. Informace o rozlišování dotazů SQLite pro případ najdete v následujících tématech:
Přejděte na /Movies/Index. Připojte řetězec dotazu, například ?searchString=Ghost k adrese URL. Zobrazí se filtrované filmy.
Pokud změníte podpis Index metody tak, aby měl název idparametr , id bude parametr odpovídat volitelnému {id} zástupného symbolu pro výchozí trasy nastavené v Program.cs.
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Změňte parametr na id a změňte všechny výskyty searchString na id.
Výše uvedená metoda Index:
public async Task<IActionResult> Index(string searchString)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
return View(await movies.ToListAsync());
}
Aktualizovaná Index metoda s parametrem id :
public async Task<IActionResult> Index(string id)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(id))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(id.ToUpper()));
}
return View(await movies.ToListAsync());
}
Název hledání teď můžete předat jako směrovací data (segment adresy URL) místo jako hodnotu řetězce dotazu.
Nemůžete ale očekávat, že uživatelé upraví adresu URL pokaždé, když chtějí hledat film. Teď tedy přidáte prvky uživatelského rozhraní, které jim pomůžou filtrovat filmy. Pokud jste změnili podpis Index metody tak, aby testoval, jak předat parametr vázaný ID na trasu, změňte ho zpět tak, aby přebírá parametr s názvem searchString:
public async Task<IActionResult> Index(string searchString)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
return View(await movies.ToListAsync());
}
Views/Movies/Index.cshtml Otevřete soubor a přidejte níže zvýrazněnou <form> značku:
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index">
<p>
<label>Title: <input type="text" name="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
Značka HTML <form> používá pomocníka značky formuláře, takže při odeslání formuláře se řetězec filtru odešle do Index akce kontroleru filmů. Uložte změny a pak filtr otestujte.
Neexistuje žádné [HttpPost] přetížení Index metody, jak byste mohli očekávat. Nepotřebujete ji, protože metoda nemění stav aplikace, jenom filtrování dat.
Můžete přidat následující [HttpPost] Index metodu.
[HttpPost]
public string Index(string searchString, bool notUsed)
{
return "From [HttpPost]Index: filter on " + searchString;
}
Parametr notUsed se používá k vytvoření přetížení pro metodu Index . O tom budeme mluvit později v tomto kurzu.
Pokud přidáte tuto metodu, vyvolání akce by odpovídalo [HttpPost] Index metodě a [HttpPost] Index metoda by se spustila, jak je znázorněno na obrázku níže.
I když ale přidáte tuto [HttpPost] verzi Index metody, existuje omezení způsobu implementace. Představte si, že chcete vytvořit záložku určitého hledání nebo chcete poslat odkaz přátelům, na které můžou kliknout, aby se zobrazil stejný filtrovaný seznam filmů. Všimněte si, že adresa URL požadavku HTTP POST je stejná jako adresa URL požadavku GET (localhost:{PORT}/Movies/Index) – v adrese URL nejsou žádné informace o hledání. Informace o vyhledávacím řetězci se odešlou na server jako hodnota pole formuláře. To můžete ověřit pomocí prohlížeče Vývojářské nástroje nebo vynikajícího nástroje Fiddler. Následující obrázek ukazuje prohlížeč Chrome Vývojářské nástroje:
V textu požadavku můžete vidět hledaný parametr a token XSRF . Všimněte si, jak je uvedeno v předchozím kurzu, pomocník značky formuláře vygeneruje antiforgery token XSRF . Neupravujeme data, takže token v metodě kontroleru nemusíme ověřovat.
Vzhledem k tomu, že parametr vyhledávání je v textu požadavku, a ne v adrese URL, nemůžete zachytit tyto informace hledání, které chcete uložit do záložek nebo sdílet s ostatními. Opravte to tak, že v souboru zadáte požadavek HTTP GETViews/Movies/Index.cshtml .
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index" method="get">
<p>
<label>Title: <input type="text" name="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
Když teď odešlete hledání, adresa URL obsahuje řetězec vyhledávacího dotazu. Hledání také přejde na metodu HttpGet Index akce, i když máte metodu HttpPost Index .
Následující kód ukazuje změnu značky form :
<form asp-controller="Movies" asp-action="Index" method="get">
Přidat hledání podle žánru
Do složky Models přidejte následující MovieGenreViewModel třídu:
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;
namespace MvcMovie.Models;
public class MovieGenreViewModel
{
public List<Movie>? Movies { get; set; }
public SelectList? Genres { get; set; }
public string? MovieGenre { get; set; }
public string? SearchString { get; set; }
}
Model zobrazení filmového žánru bude obsahovat:
- Seznam filmů.
- A
SelectListobsahující seznam žánrů. Uživatel tak může ze seznamu vybrat žánr. -
MovieGenre, který obsahuje vybraný žánr. -
SearchString, který obsahuje text, který uživatel zadá do vyhledávacího textového pole.
Nahraďte metodu IndexMoviesController.cs následujícím kódem:
// GET: Movies
public async Task<IActionResult> Index(string movieGenre, string searchString)
{
if (_context.Movie == null)
{
return Problem("Entity set 'MvcMovieContext.Movie' is null.");
}
// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
var movies = from m in _context.Movie
select m;
if (!string.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.ToUpper().Contains(searchString.ToUpper()));
}
if (!string.IsNullOrEmpty(movieGenre))
{
movies = movies.Where(x => x.Genre == movieGenre);
}
var movieGenreVM = new MovieGenreViewModel
{
Genres = new SelectList(await genreQuery.Distinct().ToListAsync()),
Movies = await movies.ToListAsync()
};
return View(movieGenreVM);
}
Následující kód je LINQ dotaz, který načte všechny žánry z databáze.
// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
Žánry SelectList se vytvářejí tak, že promítnou různé žánry (nechceme, aby náš výběrový seznam měl duplicitní žánry).
Když uživatel vyhledá položku, hodnota hledání se zachovají do vyhledávacího pole.
Přidání vyhledávání podle žánru do zobrazení indexu
Aktualizace Index.cshtml nalezená v zobrazeních/filmy/ následujícím způsobem:
@model MvcMovie.Models.MovieGenreViewModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index" method="get">
<p>
<select asp-for="MovieGenre" asp-items="Model.Genres">
<option value="">All</option>
</select>
<label>Title: <input type="text" asp-for="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movies![0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies![0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies![0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies![0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movies!)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Prozkoumejte výraz lambda použitý v následujícím pomocníkovi HTML:
@Html.DisplayNameFor(model => model.Movies![0].Title)
V předchozím kódu DisplayNameFor pomocník HTML zkontroluje Title vlastnost odkazovanou ve výrazu lambda, aby určil zobrazovaný název. Vzhledem k tomu, že výraz lambda se kontroluje místo vyhodnocení, neobdržíte porušení přístupu, pokud model, model.Moviesnebo jsou nebo jsou nebo model.Movies[0] jsou null prázdné. Při vyhodnocování výrazu lambda (například @Html.DisplayFor(modelItem => item.Title)) se vyhodnocují hodnoty vlastností modelu. Následující ! je model.Movies null-forgiving, který se používá k deklaraci, že není null.Movies
Otestujte aplikaci vyhledáváním podle žánru, podle názvu filmu a obojího:
V této části přidáte funkci vyhledávání do Index metody akce, která umožňuje hledat filmy podle žánru nebo názvu.
Aktualizujte metodu Index nalezenou v Controllers/MoviesController.cs následujícím kódu:
public async Task<IActionResult> Index(string searchString)
{
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.Contains(searchString));
}
return View(await movies.ToListAsync());
}
První řádek Index metody akce vytvoří dotaz LINQ pro výběr filmů:
var movies = from m in _context.Movie
select m;
Dotaz je definován pouze v tomto okamžiku, nebyl spuštěn proti databázi.
searchString Pokud parametr obsahuje řetězec, dotaz filmy se upraví tak, aby filtrovaly hodnotu hledaného řetězce:
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.Contains(searchString));
}
Výše s => s.Title!.Contains(searchString) uvedený kód je výraz lambda. Lambda se používají v dotazech LINQ založených na Dotazy LINQ se nespouštějí, když jsou definovány nebo když jsou upraveny voláním metody, jako Whereje , Containsnebo OrderBy. Místo toho se odloží provádění dotazu. To znamená, že vyhodnocení výrazu je zpožděné, dokud se jeho dosažená hodnota ve skutečnosti iterated over nebo ToListAsync metoda volá. Další informace o odložené spuštění dotazu naleznete v tématu Provádění dotazů.
Poznámka: Metoda Contains se spouští v databázi, ne v kódu c#uvedeném výše. Citlivost případu na dotazu závisí na databázi a kolaci. Na SQL Serveru Contains se mapuje na SQL LIKE, což je nerozlišující velká a malá písmena. U SQLite s výchozí kolací se rozlišují malá a velká písmena.
Přejděte na /Movies/Index. Připojte řetězec dotazu, například ?searchString=Ghost k adrese URL. Zobrazí se filtrované filmy.
Pokud změníte podpis Index metody tak, aby měl název idparametr , id bude parametr odpovídat volitelnému {id} zástupného symbolu pro výchozí trasy nastavené v Program.cs.
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
Změňte parametr na id a změňte všechny výskyty searchString na id.
Výše uvedená metoda Index:
public async Task<IActionResult> Index(string searchString)
{
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.Contains(searchString));
}
return View(await movies.ToListAsync());
}
Aktualizovaná Index metoda s parametrem id :
public async Task<IActionResult> Index(string id)
{
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(id))
{
movies = movies.Where(s => s.Title!.Contains(id));
}
return View(await movies.ToListAsync());
}
Název hledání teď můžete předat jako směrovací data (segment adresy URL) místo jako hodnotu řetězce dotazu.
Nemůžete ale očekávat, že uživatelé upraví adresu URL pokaždé, když chtějí hledat film. Teď tedy přidáte prvky uživatelského rozhraní, které jim pomůžou filtrovat filmy. Pokud jste změnili podpis Index metody tak, aby testoval, jak předat parametr vázaný ID na trasu, změňte ho zpět tak, aby přebírá parametr s názvem searchString:
public async Task<IActionResult> Index(string searchString)
{
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title!.Contains(searchString));
}
return View(await movies.ToListAsync());
}
Views/Movies/Index.cshtml Otevřete soubor a přidejte níže zvýrazněnou <form> značku:
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index">
<p>
<label>Title: <input type="text" name="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
Značka HTML <form> používá pomocníka značky formuláře, takže při odeslání formuláře se řetězec filtru odešle do Index akce kontroleru filmů. Uložte změny a pak filtr otestujte.
Neexistuje žádné [HttpPost] přetížení Index metody, jak byste mohli očekávat. Nepotřebujete ji, protože metoda nemění stav aplikace, jenom filtrování dat.
Můžete přidat následující [HttpPost] Index metodu.
[HttpPost]
public string Index(string searchString, bool notUsed)
{
return "From [HttpPost]Index: filter on " + searchString;
}
Parametr notUsed se používá k vytvoření přetížení pro metodu Index . O tom budeme mluvit později v tomto kurzu.
Pokud přidáte tuto metodu, vyvolání akce by odpovídalo [HttpPost] Index metodě a [HttpPost] Index metoda by se spustila, jak je znázorněno na obrázku níže.
I když ale přidáte tuto [HttpPost] verzi Index metody, existuje omezení způsobu implementace. Představte si, že chcete vytvořit záložku určitého hledání nebo chcete poslat odkaz přátelům, na které můžou kliknout, aby se zobrazil stejný filtrovaný seznam filmů. Všimněte si, že adresa URL požadavku HTTP POST je stejná jako adresa URL požadavku GET (localhost:{PORT}/Movies/Index) – v adrese URL nejsou žádné informace o hledání. Informace o vyhledávacím řetězci se odešlou na server jako hodnota pole formuláře. To můžete ověřit pomocí prohlížeče Vývojářské nástroje nebo vynikajícího nástroje Fiddler. Následující obrázek ukazuje prohlížeč Chrome Vývojářské nástroje:
V textu požadavku můžete vidět hledaný parametr a token XSRF . Všimněte si, jak je uvedeno v předchozím kurzu, pomocník značky formuláře vygeneruje antiforgery token XSRF . Neupravujeme data, takže token v metodě kontroleru nemusíme ověřovat.
Vzhledem k tomu, že parametr vyhledávání je v textu požadavku, a ne v adrese URL, nemůžete zachytit tyto informace hledání, které chcete uložit do záložek nebo sdílet s ostatními. Opravte to tak, že v souboru zadáte požadavek HTTP GETViews/Movies/Index.cshtml .
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index" method="get">
<p>
<label>Title: <input type="text" name="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
Když teď odešlete hledání, adresa URL obsahuje řetězec vyhledávacího dotazu. Hledání také přejde na metodu HttpGet Index akce, i když máte metodu HttpPost Index .
Následující kód ukazuje změnu značky form :
<form asp-controller="Movies" asp-action="Index" method="get">
Přidat hledání podle žánru
Do složky Models přidejte následující MovieGenreViewModel třídu:
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;
namespace MvcMovie.Models
{
public class MovieGenreViewModel
{
public List<Movie>? Movies { get; set; }
public SelectList? Genres { get; set; }
public string? MovieGenre { get; set; }
public string? SearchString { get; set; }
}
}
Model zobrazení filmového žánru bude obsahovat:
- Seznam filmů.
- A
SelectListobsahující seznam žánrů. Uživatel tak může ze seznamu vybrat žánr. -
MovieGenre, který obsahuje vybraný žánr. -
SearchString, který obsahuje text, který uživatel zadá do vyhledávacího textového pole.
Nahraďte metodu IndexMoviesController.cs následujícím kódem:
// GET: Movies
public async Task<IActionResult> Index(string movieGenre, string searchString)
{
// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
var movies = from m in _context.Movie
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);
}
var movieGenreVM = new MovieGenreViewModel
{
Genres = new SelectList(await genreQuery.Distinct().ToListAsync()),
Movies = await movies.ToListAsync()
};
return View(movieGenreVM);
}
Následující kód je LINQ dotaz, který načte všechny žánry z databáze.
// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
Žánry SelectList se vytvářejí tak, že promítnou různé žánry (nechceme, aby náš výběrový seznam měl duplicitní žánry).
Když uživatel vyhledá položku, hodnota hledání se zachovají do vyhledávacího pole.
Přidání vyhledávání podle žánru do zobrazení indexu
Aktualizace Index.cshtml nalezená v zobrazeních/filmy/ následujícím způsobem:
@model MvcMovie.Models.MovieGenreViewModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index" method="get">
<p>
<select asp-for="MovieGenre" asp-items="Model.Genres">
<option value="">All</option>
</select>
<label>Title: <input type="text" asp-for="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movies[0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies[0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies[0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies[0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movies)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Prozkoumejte výraz lambda použitý v následujícím pomocníkovi HTML:
@Html.DisplayNameFor(model => model.Movies[0].Title)
V předchozím kódu DisplayNameFor pomocník HTML zkontroluje Title vlastnost odkazovanou ve výrazu lambda, aby určil zobrazovaný název. Vzhledem k tomu, že výraz lambda se kontroluje místo vyhodnocení, neobdržíte porušení přístupu, pokud model, model.Moviesnebo jsou nebo jsou nebo model.Movies[0] jsou null prázdné. Při vyhodnocování výrazu lambda (například @Html.DisplayFor(modelItem => item.Title)) se vyhodnocují hodnoty vlastností modelu.
Otestujte aplikaci vyhledáváním podle žánru, podle názvu filmu a obojího:
V této části přidáte funkci vyhledávání do Index metody akce, která umožňuje hledat filmy podle žánru nebo názvu.
Aktualizujte metodu Index nalezenou v Controllers/MoviesController.cs následujícím kódu:
public async Task<IActionResult> Index(string searchString)
{
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
return View(await movies.ToListAsync());
}
První řádek Index metody akce vytvoří dotaz LINQ pro výběr filmů:
var movies = from m in _context.Movie
select m;
Dotaz je definován pouze v tomto okamžiku, nebyl spuštěn proti databázi.
searchString Pokud parametr obsahuje řetězec, dotaz filmy se upraví tak, aby filtrovaly hodnotu hledaného řetězce:
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
Výše s => s.Title.Contains() uvedený kód je výraz lambda. Lambda se používají v dotazech LINQ založených na Dotazy LINQ se nespouštějí, když jsou definovány nebo když jsou upraveny voláním metody, jako Whereje , Containsnebo OrderBy. Místo toho se odloží provádění dotazu. To znamená, že vyhodnocení výrazu je zpožděné, dokud se jeho dosažená hodnota ve skutečnosti iterated over nebo ToListAsync metoda volá. Další informace o odložené spuštění dotazu naleznete v tématu Provádění dotazů.
Poznámka: Metoda Contains se spouští v databázi, ne v kódu c#uvedeném výše. Citlivost případu na dotazu závisí na databázi a kolaci. Na SQL Serveru Contains se mapuje na SQL LIKE, což je nerozlišující velká a malá písmena. U SQLite s výchozí kolací se rozlišují malá a velká písmena.
Přejděte na /Movies/Index. Připojte řetězec dotazu, například ?searchString=Ghost k adrese URL. Zobrazí se filtrované filmy.
Pokud změníte podpis Index metody tak, aby měl název idparametr , id bude parametr odpovídat volitelnému {id} zástupného symbolu pro výchozí trasy nastavené v Startup.cs.
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
Změňte parametr na id a všechny výskyty searchString změn na id.
Výše uvedená metoda Index:
public async Task<IActionResult> Index(string searchString)
{
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
return View(await movies.ToListAsync());
}
Aktualizovaná Index metoda s parametrem id :
public async Task<IActionResult> Index(string id)
{
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(id))
{
movies = movies.Where(s => s.Title.Contains(id));
}
return View(await movies.ToListAsync());
}
Název hledání teď můžete předat jako směrovací data (segment adresy URL) místo jako hodnotu řetězce dotazu.
Nemůžete ale očekávat, že uživatelé upraví adresu URL pokaždé, když chtějí hledat film. Teď tedy přidáte prvky uživatelského rozhraní, které jim pomůžou filtrovat filmy. Pokud jste změnili podpis Index metody tak, aby testoval, jak předat parametr vázaný ID na trasu, změňte ho zpět tak, aby přebírá parametr s názvem searchString:
public async Task<IActionResult> Index(string searchString)
{
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
return View(await movies.ToListAsync());
}
Views/Movies/Index.cshtml Otevřete soubor a přidejte níže zvýrazněnou <form> značku:
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index">
<p>
<label>Title: <input type="text" name="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
<thead>
Značka HTML <form> používá pomocníka značky formuláře, takže při odeslání formuláře se řetězec filtru odešle do Index akce kontroleru filmů. Uložte změny a pak filtr otestujte.
Neexistuje žádné [HttpPost] přetížení Index metody, jak byste mohli očekávat. Nepotřebujete ji, protože metoda nemění stav aplikace, jenom filtrování dat.
Můžete přidat následující [HttpPost] Index metodu.
[HttpPost]
public string Index(string searchString, bool notUsed)
{
return "From [HttpPost]Index: filter on " + searchString;
}
Parametr notUsed se používá k vytvoření přetížení pro metodu Index . O tom budeme mluvit později v tomto kurzu.
Pokud přidáte tuto metodu, vyvolání akce by odpovídalo [HttpPost] Index metodě a [HttpPost] Index metoda by se spustila, jak je znázorněno na obrázku níže.
I když ale přidáte tuto [HttpPost] verzi Index metody, existuje omezení způsobu implementace. Představte si, že chcete vytvořit záložku určitého hledání nebo chcete poslat odkaz přátelům, na které můžou kliknout, aby se zobrazil stejný filtrovaný seznam filmů. Všimněte si, že adresa URL požadavku HTTP POST je stejná jako adresa URL požadavku GET (localhost:{PORT}/Movies/Index) – v adrese URL nejsou žádné informace o hledání. Informace o vyhledávacím řetězci se odešlou na server jako hodnota pole formuláře. To můžete ověřit pomocí prohlížeče Vývojářské nástroje nebo vynikajícího nástroje Fiddler. Následující obrázek ukazuje prohlížeč Chrome Vývojářské nástroje:
V textu požadavku můžete vidět hledaný parametr a token XSRF . Všimněte si, jak je uvedeno v předchozím kurzu, pomocník značky formuláře vygeneruje antiforgery token XSRF . Neupravujeme data, takže token v metodě kontroleru nemusíme ověřovat.
Vzhledem k tomu, že parametr vyhledávání je v textu požadavku, a ne v adrese URL, nemůžete zachytit tyto informace hledání, které chcete uložit do záložek nebo sdílet s ostatními. Opravte to tak, že v souboru zadáte požadavek HTTP GETViews/Movies/Index.cshtml .
@model IEnumerable<MvcMovie.Models.Movie>
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index" method="get">
<p>
<label>Title: <input type="text" name="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Title)
Když teď odešlete hledání, adresa URL obsahuje řetězec vyhledávacího dotazu. Hledání také přejde na metodu HttpGet Index akce, i když máte metodu HttpPost Index .
Následující kód ukazuje změnu značky form :
<form asp-controller="Movies" asp-action="Index" method="get">
Přidat hledání podle žánru
Do složky Models přidejte následující MovieGenreViewModel třídu:
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;
namespace MvcMovie.Models
{
public class MovieGenreViewModel
{
public List<Movie> Movies { get; set; }
public SelectList Genres { get; set; }
public string MovieGenre { get; set; }
public string SearchString { get; set; }
}
}
Model zobrazení filmového žánru bude obsahovat:
- Seznam filmů.
- A
SelectListobsahující seznam žánrů. Uživatel tak může ze seznamu vybrat žánr. -
MovieGenre, který obsahuje vybraný žánr. -
SearchString, který obsahuje text, který uživatel zadá do vyhledávacího textového pole.
Nahraďte metodu IndexMoviesController.cs následujícím kódem:
// GET: Movies
public async Task<IActionResult> Index(string movieGenre, string searchString)
{
// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
var movies = from m in _context.Movie
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);
}
var movieGenreVM = new MovieGenreViewModel
{
Genres = new SelectList(await genreQuery.Distinct().ToListAsync()),
Movies = await movies.ToListAsync()
};
return View(movieGenreVM);
}
Následující kód je LINQ dotaz, který načte všechny žánry z databáze.
// Use LINQ to get list of genres.
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
Žánry SelectList se vytvářejí tak, že promítnou různé žánry (nechceme, aby náš výběrový seznam měl duplicitní žánry).
Když uživatel vyhledá položku, hodnota hledání se zachovají do vyhledávacího pole.
Přidání vyhledávání podle žánru do zobrazení indexu
Aktualizace Index.cshtml nalezená v zobrazeních/filmy/ následujícím způsobem:
@model MvcMovie.Models.MovieGenreViewModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index" method="get">
<p>
<select asp-for="MovieGenre" asp-items="Model.Genres">
<option value="">All</option>
</select>
<label>Title: <input type="text" asp-for="SearchString" /></label>
<input type="submit" value="Filter" />
</p>
</form>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movies[0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies[0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies[0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movies[0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movies)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Prozkoumejte výraz lambda použitý v následujícím pomocníkovi HTML:
@Html.DisplayNameFor(model => model.Movies[0].Title)
V předchozím kódu DisplayNameFor pomocník HTML zkontroluje Title vlastnost odkazovanou ve výrazu lambda, aby určil zobrazovaný název. Vzhledem k tomu, že výraz lambda se kontroluje místo vyhodnocení, neobdržíte porušení přístupu, pokud model, model.Moviesnebo jsou nebo jsou nebo model.Movies[0] jsou null prázdné. Při vyhodnocování výrazu lambda (například @Html.DisplayFor(modelItem => item.Title)) se vyhodnocují hodnoty vlastností modelu.
Otestujte aplikaci vyhledáváním podle žánru, podle názvu filmu a obojího: