搜尋
注意
本教學課程的更新版本可在此取得,它使用最新版的 Visual Studio。 新的教學課程會使用 ASP.NET Core MVC,它在本教學課程提供多種改良。
本教學課程可讓您了解 ASP.NET Core MVC 與控制器和檢視。 Razor 頁面是 ASP.NET Core 中的新替代方案,它是以頁面為基礎的程式設計模型,可讓 Web UI 的建立更容易且更有效率。 建議您在嘗試使用 MVC 版本之前,先試試 Razor 頁面教學課程。 Razor 頁面教學課程:
- 比較容易學習。
- 涵蓋更多功能。
- 是開發新應用程式的建議方法。
新增搜尋方法和搜尋檢視
在本節中,您會將搜尋功能新增至 Index
動作方法,讓您依據類型或名稱搜尋電影。
必要條件
為了與本節的螢幕擷取畫面相符,您需要執行應用程式 (按 F5),並將下列電影新增至資料庫。
標題 | 發行日期 | Genre | 價格 |
---|---|---|---|
Ghostbusters | 1984 年 6 月 8 日 | 喜劇 | 6.99 |
Ghostbusters II | 1989 年 6 月 16 日 | 喜劇 | 6.99 |
Planet of the Apes | 1986 年 3 月 27 日 | 動作 | 5.99 |
更新索引表單
首先,將 Index
動作方法更新為現有的 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
參數包含字串,則系統會使用下列程式碼修改電影查詢,藉此篩選搜尋字串的值:
if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString));
}
上述 s => s.Title
程式碼是 Lambda 運算式。 在以方法為基礎的 LINQ 查詢中,Lambda 會在標準查詢運算子方法 (例如上述程式碼的 Where 方法) 中當作引數。 在您定義 LINQ 查詢,或藉由呼叫 Where
或 OrderBy
這類方法修改 LINQ 查詢時,它並不會執行。 反之,查詢的執行會延遲,也就是指延遲評估運算式,直到系統實際反覆運算它實現的值或呼叫 ToList
方法為止。 在 Search
範例中,查詢會在 Index.cshtml 檢視執行。 如需延後查詢執行的詳細資訊,請參閱查詢執行。
接下來,您可以更新 Index
檢視,向使用者顯示表單。
執行應用程式,並前往 /Movies/Index。 將查詢字串 (例如 ?searchString=ghost
) 附加至 URL。 隨即顯示篩選過的電影。
如果您將 Index
方法的簽章變更為包含名為 id
的參數,則 id
參數會按照 App_Start\RouteConfig.cs 檔案所設定的預設路由來比對 {id}
預留位置。
{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。 因此,現在您將新增可協助他們篩選電影的 UI。 如果您已變更 Index
方法的簽章來測試如何傳遞路由繫結的 ID 參數,請將變回原狀,讓 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 的 [Index] 檢視開啟時 (如上圖所示),點選 Ctr+F5 或 F5 執行應用程式,然後嘗試搜尋電影。
Index
方法沒有 HttpPost
多載。 您不需要多載,因為此方法不會變更應用程式的狀態,只會篩選資料。
您可以新增下列 HttpPost Index
方法。 這種情況下,動作啟動程式會比對 HttpPost Index
方法,而 HttpPost Index
方法會如下列影像所示執行。
[HttpPost]
public string Index(FormCollection fc, string searchString)
{
return "<h3> From [HttpPost]Index: " + searchString + "</h3>";
}
不過,即使您新增這個 HttpPost
版本的 Index
方法,在如何全部實作此方法方面仍然有其限制。 假設您想要將特定的搜尋加為書籤,或者想要傳送連結給朋友,讓他們可以點選來查看相同的電影篩選清單。 請注意,HTTP POST 要求的 URL 與 GET 要求的 URL (localhost:xxxxx/Movies/Index) 相同 -- URL 本身沒有搜尋資訊。 此時,搜尋字串資訊會以表單欄位值的形式傳送至伺服器。 這表示您無法擷取該搜尋資訊,以便加入書籤或以 URL 傳送給好友。
解決方案是使用 BeginForm
的多載,指定 POST 要求應將搜尋資訊新增至 URL,且應路由至 Index
方法的 HttpGet
版本。 以下列標記取代現有的無參數 BeginForm
方法:
@using (Html.BeginForm("Index","Movies",FormMethod.Get))
現在,如果您提交搜尋,URL 會包含搜尋查詢字串。 即使您有 HttpPost Index
方法,搜尋也會移至 HttpGet Index
動作方法。
新增以類型為依據的搜尋
如果您已新增 Index
方法的 HttpPost
版本,請先將它刪除。
接下來,您會新增一項功能,讓使用者依據類型搜尋電影。 以下列程式碼取代 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;
程式碼會使用一般的 List
集合的 AddRange
方法,將所有不同類型新增至清單。 (如果沒有 Distinct
修飾詞,系統會新增重複的類型,例如在我們的範例中,喜劇就會新增兩次)。 程式碼接著會將類型清單儲存在 ViewBag.MovieGenre
物件中。 在 ViewBag
將類別資料 (例如電影類型) 儲存為 SelectList 物件,然後在下拉式清單方塊中存取類別資料,是 MVC 應用程式的常見方法。
下列程式碼示範如何檢查 movieGenre
參數。 如果參數不是空白,程式碼會進一步縮限電影查詢,將選取的電影限制為指定類型。
if (!string.IsNullOrEmpty(movieGenre))
{
movies = movies.Where(x => x.Genre == movieGenre);
}
如先前所述,除非電影清單經過反覆查詢 (在 Index
動作方法傳回之後,於「檢視」中發生),否則系統不會對資料庫執行查詢。
將標記新增到 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
協助程式提供在 ViewBag
尋找 IEnumerable<SelectListItem>
的索引鍵。 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」提供選項標籤。 如果您在瀏覽器中檢查該選擇,會看到它的「值」屬性是空白。 由於控制器只會將 if
字串篩選為不是 null
或空白,針對 movieGenre
提交空白值就會顯示所有類型。
您也可以設定一個預設已選取的選項。 如果您想要將 「Comedy」 設為預設選項,您會將控制器的程式碼變更如下:
ViewBag.movieGenre = new SelectList(GenreLst, "Comedy");
執行應用程式並前往 /Movies/Index。 嘗試依據類型、電影名稱及同時選取這兩個條件進行搜尋。
在本節,您已建立搜尋動作方法和檢視,讓使用者可依據電影標題和類型進行搜尋。 在下一節,您將瞭解如何將屬性新增至 Movie
模型,以及如何新增初始設定式來自動建立測試資料庫。