ASP.NET Core 中文文档 第二章 指南(4.7)添加搜索
原文:Adding Search
作者:Rick Anderson
翻译:魏美娟(初见)
校对:谢炀(Kiler) 、孟帅洋(书缘)、张仁建(第二年.夏)
在本节中,你可以为 Index
方法添加查询功能,使其能够根据电影的 genre 或 name 进行查找。
更新 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 语句在定义或调用类似 Where
、Contains
或者 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)添加搜索的更多相关文章
- ASP.NET Core 中文文档 第二章 指南(4.6)Controller 方法与视图
原文:Controller methods and views 作者:Rick Anderson 翻译:谢炀(Kiler) 校对:孟帅洋(书缘) .张仁建(第二年.夏) .许登洋(Seay) .姚阿勇 ...
- ASP.NET Core 中文文档 第二章 指南(4.4)添加 Model
原文:Adding a model 作者:Rick Anderson 翻译:娄宇(Lyrics) 校对:许登洋(Seay).孟帅洋(书缘).姚阿勇(Mr.Yao).夏申斌 在这一节里,你将添加一些类来 ...
- ASP.NET Core 中文文档 第二章 指南 (09) 使用 Swagger 生成 ASP.NET Web API 在线帮助测试文档
原文:ASP.NET Web API Help Pages using Swagger 作者:Shayne Boyer 翻译:谢炀(kiler) 翻译:许登洋(Seay) 对于开发人员来说,构建一个消 ...
- 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 ...
- 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 ...
- ASP.NET Core 中文文档 第二章 指南(3)用 Visual Studio 发布一个 Azure 云 Web 应用程序
原文:Getting Started 作者:Rick Anderson 翻译:谢炀(Kiler) 校对:孟帅洋(书缘).刘怡(AlexLEWIS).何镇汐 设置开发环境 安装最新版本的 Azure S ...
- 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 ...
- ASP.NET Core 中文文档 第二章 指南(4.5)使用 SQL Server LocalDB
原文:Working with SQL Server LocalDB 作者:Rick Anderson 翻译: 魏美娟(初见) 校对: 孟帅洋(书缘).张硕(Apple).许登洋(Seay) Appl ...
- ASP.NET Core 中文文档 第二章 指南(5) 在 Nano Server 上运行ASP.NET Core
原文 ASP.NET Core on Nano Server 作者 Sourabh Shirhatti 翻译 娄宇(Lyrics) 校对 刘怡(AlexLEWIS).许登洋(Seay).谢炀(kile ...
- ASP.NET Core 中文文档 第二章 指南(8) 使用 dotnet watch 开发 ASP.NET Core 应用程序
原文:Developing ASP.NET Core applications using dotnet watch 作者:Victor Hurdugaci 翻译:谢炀(Kiler) 校对:刘怡(Al ...
随机推荐
- JdbcTemplate+PageImpl实现多表分页查询
一.基础实体 @MappedSuperclass public abstract class AbsIdEntity implements Serializable { private static ...
- .NET平台开源项目速览(18)C#平台JSON实体类生成器JSON C# Class Generator
去年,我在一篇文章用原始方法解析复杂字符串,json一定要用JsonMapper么?中介绍了简单的JSON解析的问题,那种方法在当时的环境是非常方便的,因为不需要生成实体类,结构很容易解析.但随着业务 ...
- Xamarin+Prism开发详解二:Xaml文件如何简单绑定Resources资源文件内容
我们知道在UWP里面有Resources文件xxx.resx,在Android里面有String.Xml文件等.那跨平台如何统一这些类别不一的资源文件以及Xaml设计文件如何绑定这些资源?应用支持多国 ...
- SDWebImage源码解读_之SDWebImageDecoder
第四篇 前言 首先,我们要弄明白一个问题? 为什么要对UIImage进行解码呢?难道不能直接使用吗? 其实不解码也是可以使用的,假如说我们通过imageNamed:来加载image,系统默认会在主线程 ...
- Javascript 代理模式模拟一个文件同步功能
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- BPM公文管理解决方案分享
一.方案概述 公文作为一种规范性文书,具有法律性.指导性.政令性强的特点,是企事业单位政令上通下达的重要方式.及时.准确.安全地处理.控制和管理公文,方能保障企事业单位正常运转,确保组织权威和政令畅通 ...
- 茂名石化BPM应用实践 ——业务协同及服务共享平台建设和应用
一.茂名石化简介 茂名石化隶属于中国石油化工集团公司,创建于1955年,是国家"一五"期间156项重点项目之一.经过50多年的发展,茂名石化已成为我国生产规模最大的炼油化工企业之一 ...
- Disque:Redis之父新开源的分布式内存作业队列
Disque是Redis之父Salvatore Sanfilippo新开源的一个分布式内存消息代理.它适应于"Redis作为作业队列"的场景,但采用了一种专用.独立.可扩展且具有容 ...
- Johnson 全源最短路径算法
解决单源最短路径问题(Single Source Shortest Paths Problem)的算法包括: Dijkstra 单源最短路径算法:时间复杂度为 O(E + VlogV),要求权值非负: ...
- Git 进阶指南(git ssh keys / reset / rebase / alias / tag / submodule )
在掌握了基础的 Git 使用 之后,可能会遇到一些常见的问题.以下是猫哥筛选总结的部分常见问题,分享给各位朋友,掌握了这些问题的中的要点之后,git 进阶也就完成了,它包含以下部分: 如何修改 ori ...