共用方式為


搜尋

注意

本教學課程的更新版本可在此取得,它使用最新版的 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 查詢,或藉由呼叫 WhereOrderBy 這類方法修改 LINQ 查詢時,它並不會執行。 反之,查詢的執行會延遲,也就是指延遲評估運算式,直到系統實際反覆運算它實現的值或呼叫 ToList 方法為止。 在 Search 範例中,查詢會在 Index.cshtml 檢視執行。 如需延後查詢執行的詳細資訊,請參閱查詢執行

注意

Contains 方法是在資料庫執行,而不是在上述 C# 程式碼執行。 Contains 會在資料庫上對應 SQL LIKE,不區分大小寫。

接下來,您可以更新 Index 檢視,向使用者顯示表單。

執行應用程式,並前往 /Movies/Index。 將查詢字串 (例如 ?searchString=ghost) 附加至 URL。 隨即顯示篩選過的電影。

SearchQryStr

如果您將 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 區段) 傳遞,而不是作為查詢字串值。

螢幕擷取畫面所示為「MVC Movie 索引」頁面。URL 欄位中是 localhost:1234/Movies/index/ghost,以紅色圈選。

但是,您不能期望使用者在每次想要搜尋電影時修改 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 會叫用正確的控制器動作方法來顯示檢視。

螢幕擷取畫面所示為 Index.cshtml 索引標籤,且方案總管已開啟。在方案總管中,子資料夾「Movies」已開啟,且 [Index.cshtml] 已選取。

在 Visual Studio 的 [Index] 檢視開啟時 (如上圖所示),點選 Ctr+F5 或 F5 執行應用程式,然後嘗試搜尋電影。

螢幕擷取畫面所示為 [Index] 頁面,其中 [標題] 欄位已輸入標題。

Index 方法沒有 HttpPost 多載。 您不需要多載,因為此方法不會變更應用程式的狀態,只會篩選資料。

您可以新增下列 HttpPost Index 方法。 這種情況下,動作啟動程式會比對 HttpPost Index 方法,而 HttpPost Index 方法會如下列影像所示執行。

[HttpPost] 
public string Index(FormCollection fc, string searchString) 
{ 
    return "<h3> From [HttpPost]Index: " + searchString + "</h3>"; 
}

SearchPostGhost

不過,即使您新增這個 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))

BeginFormPost_SM

現在,如果您提交搜尋,URL 會包含搜尋查詢字串。 即使您有 HttpPost Index 方法,搜尋也會移至 HttpGet Index 動作方法。

IndexWithGetURL

新增以類型為依據的搜尋

如果您已新增 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。 嘗試依據類型、電影名稱及同時選取這兩個條件進行搜尋。

螢幕擷取畫面所示為 Index 頁面,其中已選取一種類型。

在本節,您已建立搜尋動作方法和檢視,讓使用者可依據電影標題和類型進行搜尋。 在下一節,您將瞭解如何將屬性新增至 Movie 模型,以及如何新增初始設定式來自動建立測試資料庫。