问题
当排序和分页都不够帮用户去找到他们想要的结果时,另外一种帮助用户找到他们想要的结果的方式是根据特殊的规则过滤。
解决方案
添加新的links 允许使用预先的条件去过滤并且使用LINQ类库去在数据中过滤。
讨论
为了添加过滤的链接,需要在Book/Index view 和BookController中做改变。
改变的View和前两个秘方差不多。需要添加HTML去允许用户去选择他们想如何过滤内容。三个连接将被添加:全部的,新发布的和即将到来的。新发布的将被定义为最近2周发布的。即将到来的就被定义为还没发布的。
下边是新的 Book/Index view。有三个link。第一个link包含当前的sortOrder,剩下的2个link包含了新的变量filter。像分页link一样。如果当前的filter是你选中的话,把他显示成静态文本而不是link,其他的fitler设置为link的形式。确保用户更改排序规则时,filter也被维护。我们的Index view 要更新成如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
@Html.Partial("_Paging") < table > < tr > < th > @Html.ActionLink("Title", "Index", new { sortOrder = ViewBag.TitleSortParam, filter = ViewBag.CurrentFilter }) </ th > < th > @Html.ActionLink("Isbn", "Index", new { sortOrder = ViewBag.IsbnSortParam, filter = ViewBag.CurrentFilter }) </ th > < th > Summary </ th > < th > @Html.ActionLink("Author", "Index", new { sortOrder = ViewBag.AuthorSortParam, filter = ViewBag.CurrentFilter }) </ th > < th > Thumbnail </ th > < th > @Html.ActionLink("Price", "Index", new { sortOrder = ViewBag.PriceSortParam, filter = ViewBag.CurrentFilter }) </ th > < th > @Html.ActionLink("Published", "Index", new { sortOrder = ViewBag.PublishedSortParam, filter = ViewBag.CurrentFilter }) </ th > < th > </ th > </ tr > @foreach (var item in Model) { < tr > < td > @Html.DisplayFor(modelItem => item.Title) </ td > < td > @Html.DisplayFor(modelItem => item.Isbn) </ td > < td > @Html.DisplayFor(modelItem => item.Summary) </ td > < td > @Html.DisplayFor(modelItem => item.Author) </ td > < td > @Html.DisplayFor(modelItem => item.Thumbnail) </ td > < td > @Html.DisplayFor(modelItem => item.Price) </ td > < td > @Html.DisplayFor(modelItem => item.Published) </ td > < td > @Html.ActionLink("Edit","Edit", new { id = item.ID }) | @Html.ActionLink("Details","Details", new { id = item.ID }) | @Html.ActionLink("Delete","Delete", new { id = item.ID }) </ td > </ tr > } </ table > @Html.Partial("_Paging") |
上一个秘方中创建的_Paging的Partial view也需要被更新。在下边的例子里,4个paging link 已经被更新成传递了当前的filter,page,和sortOrder。以下是_Paging更新后的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
< p > @if (Model.HasPreviousPage) { @Html.ActionLink("<< First ", "Index", new { page = 1 , sortOrder = ViewBag .CurrentSortOrder, filter = ViewBag .CurrentFilter }) @Html.Raw(" "); @Html.ActionLink("< Prev", "Index", new { page = Model .PageNumber - 1, sortOrder = ViewBag .CurrentSortOrder, filter = ViewBag .CurrentFilter }) } else { @:<< First @Html.Raw(" "); @:< Prev } @if (Model.HasNextPage) { @Html.ActionLink("Next >", "Index", new { page = Model.PageNumber + 1, sortOrder = ViewBag.CurrentSortOrder, filter = ViewBag.CurrentFilter }) @Html.Raw(" "); @Html.ActionLink("Last >>", "Index", new { page = Model.PageCount, sortOrder = ViewBag.CurrentSortOrder, filter = ViewBag.CurrentFilter }) } else { @:Next > @Html.Raw(" ") @:Last >> } </ p > |
接下来我们要改变BooksController,在Index()Action 中更改代码。新接收一个filter变量。图书的列表将基于用户选择的filter选项被缩减。有2中方法实现filter。
- 再次使用动态Linq库 的where子句。
- 使用标准的Linq 和一个switch块去创建一个强类型的子句。
由于传统的filter link并不包含太多的条目,这个秘方,我们选择用第二种实现方法。这样做的好处是,我们不需要考虑SQL注入的问题,因为他是强类型的,并且不是动态的。
以下是BooksController部分代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity; using System.Linq; using System.Linq.Dynamic; using System.Web; using System.Web.Mvc; using MvcApplication.Models; using MvcApplication.Utils; using PagedList; namespace MvcApplication.Controllers { public class BooksController : Controller { private BookDBContext db = new BookDBContext(); // // GET: /Books/ public ViewResult Index(string sortOrder,string filter, int page = 1) { #region ViewBag Resources #endregion #region ViewBag Sort Params #endregion var books = from b in db.Books select b; #region Filter Switch switch (filter) { case "NewReleases": var startDate = DateTime.Today.AddDays(-14); books = books.Where(b => b.Published <= DateTime.Today.Date && b.Published >= startDate ); break; case "ComingSoon": books = books.Where(b => b.Published > DateTime.Today.Date); break; default: // No filter needed break; } ViewBag.CurrentFilter = String.IsNullOrEmpty(filter) ? "" : filter; #endregion books = books.OrderBy(sortOrder); const int maxRecords = 2; var currentPage = page <= 0 ? 1 : page; return View(books.ToPagedList(currentPage,maxRecords)); } } } |
在上边的例子里,如果用户选择NewReleases 这个filter,这个搜索将返回今天或者14天之内出版的书。或者用户选择了Coming soon,搜索将返回即将出版的书。