首页 > 代码库 > 学习ASP.NET MVC(七)——我的第一个ASP.NET MVC 查询页面

学习ASP.NET MVC(七)——我的第一个ASP.NET MVC 查询页面

       在本篇文章中,我将添加一个新的查询页面(SearchIndex),可以按书籍的种类或名称来进行查询。这个新页面的网址是http://localhost:36878/Book/ SearchIndex。该页面中用一个下拉框来显示种类,用一文本框让用户输入书籍的名称。当用户在点击“查询”按钮之后,页面会被刷新,显示用户的查询结果。控制器会根据用户提交查询参数,由动作方法(Action Motehd)去解析用户提交的参数值,并使用这些值来查询数据库。

第一步,创建SearchIndex查询页面
            首先,在BookController中添加一个SearchIndex动作方法。该方法将返回一个包含HTML表单的视图。代码如下:

public ActionResult SearchIndex(string searchString)        {           var books = from m in db.Books                        select m;           if (!String.IsNullOrEmpty(searchString))           {                books = books.Where(s => s.Name.Contains(searchString));            }            return View(books);        }

        上面SearchIndex方法代码中的第一行如下面,其作用是创建一个LINQ查询从数据库中筛选相应的书籍数据:

           var books = from m in db.Books                       select m;

       这一句表示查询已经建立,但是尚未对数据存储区中的数据进行筛选。 
       如果“searchString”参数变量中有一个字符串,则这个“books”查询语句将以“searchString”参数变量的值做为查询条件进行筛选相应的书籍数据,如下面的代码:

   if (!String.IsNullOrEmpty(searchString))            {               books = books.Where(s => s.Name.Contains(searchString));            }

       上面代码中的s =>s.Title代码是一个Lambda表达式。 Lambda 表达式用在基于方法的 LINQ 查询中,作为诸如 Where 和 Where 等标准查询运算符方法的参数。  例如上面的代码中使用的方法。LINQ查询时未执行它们的定义,或者当他们通过调用一个方法进行修改,或在排序时进行修改。相反,查询执行的延迟,这意味着一个表达式的计算被延迟,直到其变量实际上的迭代结束或者可以调用的方法(ToList方法)被调用。在SearchIndex这个页面中,查询是在SearchIndex视图下执行。

       接下来,我们来制作一个SearchIndex视图,以将这个查询界面呈现给用户看。在Visual Studio中的BookController文件中右键单击里面的SearchIndex方法,在弹出菜单中单击“添加视图”菜单。在添加视图对话框中,指定你要一个Book对象传递给视图模板作为它的模型类。在支架模板列表中,选择列表,然后单击“添加”。如下图。

 

 

        当单击“添加”按钮,将创建一个Views\Book\ SearchIndex.cshtml视图模板。因为你选择了列表中的支架模板列表中,Visual Studio会自动生成(搭建)的视图中的一些默认的标记。基架创建一个HTML表单。它检查Book类和创建的代码来呈现为类的每个属性<label>元素。下面的清单显示生成的创建视图:

 

@model IEnumerable<MvcApplication1.Models.Book>@{    ViewBag.Title = "书籍查询";}<h2>书籍查询</h2><p>    @Html.ActionLink("Create New", "Create")</p><table>    <tr>        <th>            @Html.DisplayNameFor(model => model.Category)        </th>        <th>            @Html.DisplayNameFor(model => model.Name)        </th>        <th>            @Html.DisplayNameFor(model => model.Numberofcopies)        </th>        <th>            @Html.DisplayNameFor(model => model.AuthorID)        </th>        <th>            @Html.DisplayNameFor(model => model.Price)        </th>        <th>            @Html.DisplayNameFor(model => model.PublishDate)        </th>        <th></th>    </tr> @foreach (var item in Model) {    <tr>        <td>            @Html.DisplayFor(modelItem => item.Category)        </td>        <td>            @Html.DisplayFor(modelItem => item.Name)        </td>        <td>            @Html.DisplayFor(modelItem => item.Numberofcopies)        </td>        <td>            @Html.DisplayFor(modelItem => item.AuthorID)        </td>        <td>            @Html.DisplayFor(modelItem => item.Price)        </td>        <td>            @Html.DisplayFor(modelItem => item.PublishDate)        </td>        <td>            @Html.ActionLink("Edit", "Edit", new { id=item.BookID }) |            @Html.ActionLink("Details", "Details", new { id=item.BookID }) |            @Html.ActionLink("Delete", "Delete", new { id=item.BookID })        </td>    </tr>}</table>

 

      按F5, 运行该应用程序,并使用浏览器导航到/Book/ SearchIndex。在URL后面会追加一个查询字符串,如“?searchString=sql”。提交之后,符合条件的书籍数据将显示。如下图。

 


 第三,修改SearchIndex查询方法
        我们也可以修改SearchIndex方法的参数,传入一个命名参数“ID”,这个“ID”参数将匹配在Global.asax文件中的缺省路由设置中的{id}占位符。路由设置如下: 

{controller}/{action}/{id}

原来SearchIndex方法如下所示:

public ActionResult SearchIndex(string searchString)      {            var books = from m in db.Books                         select m;            if (!String.IsNullOrEmpty(searchString))            {                books = books.Where(s => s.Name.Contains(searchString));            }            return View(books);        }

       修改后的SearchIndex方法将如下所示:

public ActionResult SearchIndex(string id) {       string searchString = id;            var books = from m in db.Books                        select m;            if (!String.IsNullOrEmpty(searchString))            {                books = books.Where(s => s.Name.Contains(searchString));            }            return View(books);}

 
         现在,您可以把查询条件“书籍名称”作为路由数据(URL中的一段字符),而不是作为查询字符串值。如下图。

 

       第三,添加“书籍名称”查询条件
     通过上面的学习,我们实现了数据查询功能。但是我们不能希望普通用户也能像我们一样,会在URL中添加查询条件。当需要进行查询时,自己去修改URL中的查询条件内容来进行书籍查询。所以,需要添加一个查询页面,方便普通用户输入相应的查询条件,根据查询条件去查询书籍。

       一、改变SearchIndex方法的签名,并通过路由绑定到ID参数上,让SearchIndex方法接受一个名为“searchString”字符串作为参数。代码如下:

public ActionResult SearchIndex(string searchString) {                  var books = from m in db.Books                         select m;            if (!String.IsNullOrEmpty(searchString))            {                books = books.Where(s => s.Name.Contains(searchString));            }            return View(books);}

 

        二、打开Views\Book\ SearchIndex.cshtml文件,在@Html.ActionLink("Create New", "Create")的位置处,添加一个文本框与一个查询按钮。内容如下: 

@using (Html.BeginForm())   {             <p> 书籍名称: @Html.TextBox("SearchString")<br />           <input type="submit" value="查询" /></p>         }

        下面的代码显示了Views\Book\ SearchIndex.cshtml文件的一部分与增加的筛选标记。 

@Model IEnumerable<MvcApplication1.Models.Book>@{    ViewBag.Title = "书籍查询";}<h2>书籍查询</h2>   @using (Html.BeginForm())   {             <p> 书籍名称: @Html.TextBox("SearchString")<br />           <input type="submit" value="查询" /></p>         }


        这个Html.BeginForm辅助方法创建了一个<form>标签。当用户通过单击“查询”按钮提交表单时,Html.BeginForm辅助方法将会把这个Form中的内容提交给控制器,同时刷新页面。
       三、按F5运行该应用程序,并在“书籍名称”文本框中输入“sql”,然后点击“查询”按钮,进行书籍查询。如下图。

       还有不需要重载SearchIndexHttpPost的方法。因为该方法不改变应用程序的状态,只是是用来查询数据。 
       你可以象下面一样把[HttpPost]加在SearchIndex方法的上面。在添加了[HttpPost]之后,浏览器将首先调用匹配HttpPostSearchIndex方法。HttpPostSearchIndex方法运行结果如下图。

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

         然而,即使添加了SearchIndex的HttpPost版本的方法。假设一下如下场景,你想把某个查询结果发给你的朋友,你又想只发一个特定链接给朋友,让他们可以查询查看相同的一个查询结果。请注意,如果是相同的查询结果,一个为HTTP POST请求,另一个为相同的URL GET请求(例如本地主机:XXXXX /图书/ SearchIndex ) 。则HTTP POST请求在URL本身没有带查询参数的情况下,是无法看到查询结果的。如果只是一个URL,这就意味着你与朋友们永远不能看到相同的查询结果。
        你应该使用以下的解决方案,使用BeginForm的重载方法,指定POST请求应该在URL中添加的相应的查询参数信息 ,它应该被路由到SearchIndex方法的HTTPGET版本。使用下面的代码替换现有参数的BeginForm方法将:如下图。

   @using (Html.BeginForm("SearchIndex", "book", FormMethod.Get))

 
       现在,当你点击“查询”按钮时,URL中将包含查询条件的字符串。查询请求也将去请求HTTPGET的 SearchIndex操作方法,即使你有一个HttpPost的SearchIndex方法。如下图。

 

第三,添加“书籍种类”查询方法
      第一步,删除代码中HttpPost版本的SearchIndex方法。 

       第二步,添加新的查询功能。在页面中添加一个“书籍种类”的查询条件,让用户可以通过“书籍种类”查询到相关书籍。用下面的代码替换SearchIndex方法:

   public ActionResult SearchIndex(string Category, string searchString)  {            var cateLst = new List<string>();            var cateQry = from d in db.Books                           orderby d.Category                           select d.Category;            cateLst.AddRange(cateQry.Distinct());            ViewBag.category = new SelectList(cateLst);            var books = from m in db.Books                         select m;            if (!String.IsNullOrEmpty(searchString))           {                books = books.Where(s => s.Name.Contains(searchString));            }            if (string.IsNullOrEmpty(Category))                return View(books);            else            {                return View(books.Where(x => x.Category == Category));            }        }

 

      这个新的SearchIndex方法增加了一个新的查询条件,即Category。代码的前几行创建一个List对象从数据库中查询“书籍种类”,并将查询到的结果添加到List对象中。

       下面的代码是通过一个LINQ查询从数据库把所有书籍种类都查了出来。  

var cateQry = from d in db.Books                           orderby d.Category                           select d.Category;


        以下代码的作用是使用泛型List集合的AddRange方法所有书籍类型添加到列表中。 (如果没有DISTINCT修饰符,会将相同的类型增加到列表中 - 例如,MS,SAP将会被我们添加两次)。

 cateLst.AddRange(cateQry.Distinct());

      然后,该代码存储在ViewBag对象流派列表。 

  ViewBag.category = new SelectList(cateLst);


     下面的代码演示如何检查Category参数。如果它不是空的,该代码进一步限制了书的查询所选择的书限制到指定的种类。      

 if (string.IsNullOrEmpty(Category))                return View(books);            else            {                return View(books.Where(x => x.Category == Category));            }

           第四,在SearchIndex查询页面中添加“书籍种类”查询条件 
          添加一个HTML样式的下拉列表框(DropDownList)到Views\Book\ SearchIndex.cshtml文件中,放在“书籍名称”文本框的前面。已完成的代码如下所示:

<p>      @using (Html.BeginForm("SearchIndex","book",FormMethod.Get)){              <p>书籍种类: @Html.DropDownList("category", "All")              书籍名称: @Html.TextBox("SearchString")            <input type="submit" value="查询" /></p>         } </p>

        按F5,运行这个应用程序,在浏览器中浏览/Book/ SearchIndex这个地址。就可以按“书籍种类”、“书籍名称”进行书籍信息查询。如下图1,图2。
 

图1

 

图2
 在本篇中学习如何创建一个新的查询操作方法和视图,让用户通过书籍名称和书籍类型来进行查询。