原文:Adding Search

作者:Rick Anderson

翻译:魏美娟(初见)

校对:谢炀(Kiler) 、孟帅洋(书缘)张仁建(第二年.夏)

在本节中,你可以为 Index 方法添加查询功能,使其能够根据电影的 genrename 进行查找。

更新 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());
}

Index 方法的第一行代码创建了一个LINQ查询,用来查找符合条件的电影:

var movies = from m in _context.Movie
select m;

这个查询 仅仅只是 在这里被定义出来,但是 并未 在数据库中执行。

如果 searchString 参数包含一个字符串,movies 查询将会添加对应查询过滤条件( 译者注 本例为 Title 包含 searchString 查询条件),代码如下:

if (!String.IsNullOrEmpty(searchString))
{
movies = movies.Where(s => s.Title.Contains(searchString)); //手工高亮
}

代码中的 s => s.Title.Contains() 是一个Lambda 表达式,Lambda 表达式被用在基于方法的LINQ查询(例如:上面代码中的Where方法 或者 Contains)中当做参数来使用。LINQ 语句在定义或调用类似 WhereContains 或者 OrderBy 的方法进行修改的时候不会执行,相反的,查询会延迟执行,这意味着一个赋值语句直到迭代完成或调用 ToListAsync 方法才具备真正的值。更多关于延时查询的信息。请参考 查询执行

注意

Contains方法是在数据库中运行的,并非在上面的 C# 代码中。在数据库中,Contains方法被翻译为不区分大小写的SQL LIKE脚本。

运行应用程序,并导航到 /Movies/Index,在 URL 后面添加一个查询字符串,例如 ?searchString=ghost,被过滤后的电影列表如下:

如果你修改 Index 方法签名使得方法包含一个名为 id 的参数,那么 id 参数将会匹配 Startup.cs 文件中的默认路由中的可选项 {id} 。

app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}"); //手工高亮
});

你可以使用 rename 操作快速的把 searchString 参数重命名为 id,在 searchString 上右击 > Rename

会被重命名的代码会高亮显示。

修改参数为 id ,其他引用到 searchString 的地方也会自动变更为 id

修改前的 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());
}

修改后的 Index 方法:

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());
}

修改完成以后,我们可以通过路由数据(URL 区块)来传递标题搜索条件而非查询字符串:

然而,你不能指望用户每次都通过修改URL来查找电影,因此你需要在界面上帮助他们过滤数据。如果你想要修改 Index 方法的签名并测试了路由绑定是如何传递 ID 参数,现在再把它改成原来的参数 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());
}
@model IEnumerable<MvcMovie.Models.Movie>

@{
ViewData["Title"] = "Index";
} <h2>Index</h2> <p>
<a asp-action="Create">Create New</a>
</p> <!--下面的整个form标签高亮-->
<form asp-controller="Movies" asp-action="Index">
<p>
Title: <input type="text" name="SearchString">
<input type="submit" value="Filter" />
</p>
</form> <table class="table">
<thead>

HTML <form> 标签使用Form Tag Helper生成,所以当你提交表单的时候,过滤字符串都被传到了 movies 控制器的 Index 方法。保存你的修改并测试过滤。

然而 Index 方法并没有你所希望的 [HttpPost] 重载。你也不需要,因为方法并不会修改应用程序的状态,仅仅只是过滤数据。

你可以添加下面的 [HttpPost] Index 方法。

[HttpPost] //手工高亮
public string Index(string searchString, bool notUsed)
{
return "From [HttpPost]Index: filter on " + searchString;
}

notUsed 参数用创建 Index 方法重载。我们在后续教程中会讨论。

如果你添加了这个方法。action 会调用匹配 [HttpPost] Index 的方法, [HttpPost] Index 方法运行结果如下所示。

然而,尽管添加了 [HttpPost] 版的 Index 方法,在实现的时候仍然存在一些局限性。设想你想将一个比较详细的查询添加书签,或者你想将查询结果以链接形式发送给朋友以便于你的朋友可以看到同样的过滤结果的电影,注意观察 HTTP POST 请求的时候,URL 是没有改变的(仍然是 localhost:xxxxx/Movies/Index),这个地址本身不包含查询信息。现在,查询信息是作为表单数据发送到服务器的,你可以通过 F12 开发者工具或者优秀的抓包工具 Fiddler tool。启动F12 开发者工具

选择 http://localhost:xxx/Movies HTTP POST 200 行点击 Body > Request Body

你可以在请求正文中看到查询参数和上一个教程中提到的XSRF令牌。Form Tag Helper生成XSRF 反伪造令牌。我们没有修改数据,所以无需在控制器方法中验证令牌。

因为查询参数在请求正文中而不是 Url 里,所以你在书签里面无法保存查询参数并共享给他人,为了解决这个问题,我们必须把请求指定为 HTTP GET。注意智能感知将帮我们更新标签。

请注意, <form> 标签中的专有标记。这种专有标记表示的标签是由Tag Helpers 支持的。

当你提交检索的时候,URL 包含查询条件,如果存在 HttpPost Index 方法,查询会跳转到 HttpGet Index 方法。

添加按照 Genre 查询

Models 目录添加下面的 MovieGenreViewModel 类:

using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic; namespace MvcMovie.Models
{
public class MovieGenreViewModel
{
public List<Movie> movies;
public SelectList genres;
public string movieGenre { get; set; }
}
}

move-genre 视图模型包含:

  • 电影列表
  • 包含 genre 列表的SelectList。允许用户从列表中选择 genre 。
  • movieGenre,包含选中的 genre

用下面的代码替换 Index 方法:

public async Task<IActionResult> Index(string movieGenre, string searchString)
{
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();
movieGenreVM.genres = new SelectList(await genreQuery.Distinct().ToListAsync());
movieGenreVM.movies = await movies.ToListAsync(); return View(movieGenreVM);
}

下面代码是通过 LINQ 语句从数据库中检索所有 genre 数据。

IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;

SelectList 的 genres 通过 Distinct 方法投影查询创建(我们不想选择列表中出现重复的数据)。

movieGenreVM.genres = new SelectList(await genreQuery.Distinct().ToListAsync());

在 Index 视图中添加通过 genre 检索

<!--手工高亮-->
@model MovieGenreViewModel
@{
ViewData["Title"] = "Index";
} <h2>Index</h2>
<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> <!--手工高亮--> Title: <input type="text" name="SearchString">
<input type="submit" value="Filter" />
</p>
</form> <table class="table">
<tr>
<th>
@Html.DisplayNameFor( model => model.movies[0].Genre ) <!--手工高亮-->
</th>
<th>
@Html.DisplayNameFor( model => model.movies[0].Price )
</th>
<th>
@Html.DisplayNameFor( model => model.movies[0].ReleaseDate )
</th>
<th>
@Html.DisplayNameFor( model => model.movies[0].Title )
</th>
<th></th>
</tr>
<tbody>
@foreach( var item in Model.movies ) //手工高亮
{
<tr>
<td>
@Html.DisplayFor( modelItem => item.Genre )
</td>
<td>
@Html.DisplayFor( modelItem => item.Price )
</td>
<td>
@Html.DisplayFor( modelItem => item.ReleaseDate )
</td>
<td>
@Html.DisplayFor( modelItem => item.Title )
</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>

测试程序并分别通过 genre 或者 电影标题以及两个条件同时进行检索

返回目录

ASP.NET Core 中文文档 第二章 指南(4.7)添加搜索的更多相关文章

  1. ASP.NET Core 中文文档 第二章 指南(4.6)Controller 方法与视图

    原文:Controller methods and views 作者:Rick Anderson 翻译:谢炀(Kiler) 校对:孟帅洋(书缘) .张仁建(第二年.夏) .许登洋(Seay) .姚阿勇 ...

  2. ASP.NET Core 中文文档 第二章 指南(4.4)添加 Model

    原文:Adding a model 作者:Rick Anderson 翻译:娄宇(Lyrics) 校对:许登洋(Seay).孟帅洋(书缘).姚阿勇(Mr.Yao).夏申斌 在这一节里,你将添加一些类来 ...

  3. ASP.NET Core 中文文档 第二章 指南 (09) 使用 Swagger 生成 ASP.NET Web API 在线帮助测试文档

    原文:ASP.NET Web API Help Pages using Swagger 作者:Shayne Boyer 翻译:谢炀(kiler) 翻译:许登洋(Seay) 对于开发人员来说,构建一个消 ...

  4. ASP.NET Core 中文文档 第二章 指南(1)用 Visual Studio Code 在 macOS 上创建首个 ASP.NET Core 应用程序

    原文:Your First ASP.NET Core Application on a Mac Using Visual Studio Code 作者:Daniel Roth.Steve Smith ...

  5. ASP.NET Core 中文文档 第二章 指南(2)用 Visual Studio 和 ASP.NET Core MVC 创建首个 Web API

    原文:Building Your First Web API with ASP.NET Core MVC and Visual Studio 作者:Mike Wasson 和 Rick Anderso ...

  6. ASP.NET Core 中文文档 第二章 指南(3)用 Visual Studio 发布一个 Azure 云 Web 应用程序

    原文:Getting Started 作者:Rick Anderson 翻译:谢炀(Kiler) 校对:孟帅洋(书缘).刘怡(AlexLEWIS).何镇汐 设置开发环境 安装最新版本的 Azure S ...

  7. ASP.NET Core 中文文档 第二章 指南(4.1)ASP.NET Core MVC 与 Visual Studio 入门

    原文:Getting started with ASP.NET Core MVC and Visual Studio 作者:Rick Anderson 翻译:娄宇(Lyrics) 校对:刘怡(Alex ...

  8. ASP.NET Core 中文文档 第二章 指南(4.5)使用 SQL Server LocalDB

    原文:Working with SQL Server LocalDB 作者:Rick Anderson 翻译: 魏美娟(初见) 校对: 孟帅洋(书缘).张硕(Apple).许登洋(Seay) Appl ...

  9. ASP.NET Core 中文文档 第二章 指南(5) 在 Nano Server 上运行ASP.NET Core

    原文 ASP.NET Core on Nano Server 作者 Sourabh Shirhatti 翻译 娄宇(Lyrics) 校对 刘怡(AlexLEWIS).许登洋(Seay).谢炀(kile ...

  10. ASP.NET Core 中文文档 第二章 指南(8) 使用 dotnet watch 开发 ASP.NET Core 应用程序

    原文:Developing ASP.NET Core applications using dotnet watch 作者:Victor Hurdugaci 翻译:谢炀(Kiler) 校对:刘怡(Al ...

随机推荐

  1. RPC 使用中的一些注意点

    最近线上碰到一点小问题,分析其原因发现是出在对 RPC 使用上的一些细节掌握不够清晰导致.很多时候我们做业务开发会把 RPC 当作黑盒机制来使用,但若不对黑盒的工作原理有个基本掌握,也容易犯一些误用的 ...

  2. 菜鸟学Struts2——零配置(Convention )

    又是周末,继续Struts2的学习,之前学习了,Struts的原理,Actions以及Results,今天对对Struts的Convention Plugin进行学习,如下图: Struts Conv ...

  3. 2017-1-5 天气雨 React 学习笔记

    官方example 中basic-click-counter <script type="text/babel"> var Counter = React.create ...

  4. 前端学HTTP之日志记录

    前面的话 几乎所有的服务器和代理都会记录下它们所处理的HTTP事务摘要.这么做出于一系列的原因:跟踪使用情况.安全性.计费.错误检测等等.本文将谥介绍日志记录 记录内容 大多数情况下,日志的记录出于两 ...

  5. Hawk 4.4 执行器

    执行器是负责将Hawk的结果传送到外部环境的工具.你可以写入数据表,数据库,甚至执行某个特定的动作,或是生成文件等等. 在调试模式下,执行器都是不工作的.这是为了避免产生副作用.否则,每刷新一遍数据, ...

  6. Redis链表实现

    链表在 Redis 中的应用非常广泛, 比如列表键的底层实现之一就是链表: 当一个列表键包含了数量比较多的元素, 又或者列表中包含的元素都是比较长的字符串时, Redis 就会使用链表作为列表键的底层 ...

  7. 设计模式之行为类模式大PK

                                        行为类模式大PK 行为类模式包括责任链模式.命令模式.解释器模式.迭代器模式.中介者模式.备忘录模式.观察者模式.状态模式.策略 ...

  8. Django

    一.Django 简介 Django 是一个由 Python 写成的开放源代码的 Web 应用框架.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是 CMS(内容管理系统) ...

  9. 通过自定义特性,使用EF6拦截器完成创建人、创建时间、更新人、更新时间的统一赋值(使用数据库服务器时间赋值,接上一篇)

    目录: 前言 设计(完成扩展) 实现效果 扩展设计方案 扩展后代码结构 集思广益(问题) 前言: 在上一篇文章我写了如何重建IDbCommandTreeInterceptor来实现创建人.创建时间.更 ...

  10. 高性能 TCP/UDP/HTTP 通信框架 HP-Socket v4.1.1

    HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP/HTTP 通信系统,提供 C/ ...