【譯】MVC3 20個秘方-(7)為結果排序
問題
你有一個很龐大的列表(例如,圖書列表),你不能很容易找到你想找的東西。以列表中某一列為基礎排序,可以幫助你更快的去找到你想要的東西。
解決方案
在book list的標題上添加一個鏈接。當用戶點擊鏈接的時候,使用Dynamic Linq Library去為結果排序,給予選擇的列。(升序或者降序)。再點一次鏈接的話,就會反轉順序。
討論
和以前我用過的框架相比較,我對于在自動生成的View里添加一個排序有點驚訝。希望在未來版本的MVC中,腳手架可以幫我們去做這件事。另一件我需要做的事就是在ASP.NET MVC 的主頁上提供一個或更多的選項可以去切換排序。在圖書的例子里,只有5個列需要被排序,也不算太糟。但是如果這個功能應用到其他的例子上??赡苁亲髡吡械龋ぷ髁烤鸵黾永玻≡谙逻叺睦?,我們如果用Dynamic Linq Library就簡單多啦!
默認的,linq 類庫 允許強類型的表達式從數據庫生成結果。這有一些優勢,比如,全方位的智能感知,編譯時錯誤消息。當然,就像我上邊說的,Build那些有用的功能也變成了很大的工作量。
為了支持排序,在BooksController 和Books index view 需要做以下更改:
@model IEnumerable<MvcApplication.Models.Book>
<h2>@ViewBag.Title</h2>
<p>
@Html.ActionLink((string)ViewBag.CreateLink, "Create")
</p>
<table>
<tr>
<th>
@Html.ActionLink((string)ViewBag.TitleDisplay,
"Index", new { sortOrder = ViewBag.TitleSortParam })
</th>
<th>
@Html.ActionLink((string)ViewBag.IsbnDisplay,
"Index", new { sortOrder = ViewBag.IsbnSortParam })
</th>
<th>
@ViewBag.SummaryDisplay
</th>
<th>
@Html.ActionLink((string)ViewBag.AuthorDisplay,
"Index", new { sortOrder = ViewBag.AuthorSortParam })
</th>
<th>
@ViewBag.ThumbnailDisplay
</th>
<th>
@Html.ActionLink((string)ViewBag.PriceDisplay,
"Index", new { sortOrder = ViewBag.PriceSortParam })
</th>
<th>
@Html.ActionLink((string)ViewBag.PublishedDisplay,
"Index", new
{
sortOrder =
ViewBag.PublishedSortParam
})
</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((string)ViewBag.EditLink,
"Edit", new { id = item.ID }) |
@Html.ActionLink((string)ViewBag.DetailsLink,
"Details", new { id = item.ID }) |
@Html.ActionLink((string)ViewBag.DeleteLink,
"Delete", new { id = item.ID })
</td>
</tr>
}
</table>
在上邊的例子中,前邊創建的<th>標簽已不再是靜態的文本。已經使用ActionLink替換成了HTML Helper中的HTML link。
接下來BookController的 Index action也需要被更新。這個action將要接收一個新的參數: sortOrder。接下來我們要使用LINQ 根據這列為結果排序。微軟已經提供了一個免費的 動態查詢類,它是linq下的擴展,允許你根據表達式動態的查詢。命名空間為using System.Linq.Dynamic。下載這個類的C#版本可以訪問:http://msdn2.microsoft.com/en-us/vcsharp/bb894665.aspx.(譯者:記得點下邊的 I accept啊?。┫螺d完,你需要解壓縮。動態linq查詢類可以在這里被找到: ~\CSharpSamples\LinqSamples\Dynamic
Query\DynamicQuery\Dynamic.cs. 這個文件一定要加到項目里。為了合理組織項目結構。我建議你把他加到Utils目錄下。右擊Utils目錄->添加->已經存在的項,并找到dynamic linq
class (或者你直接把那個文件夾拖拽到Utils目錄下)。
添加完成后,按照如下代碼更新BooksController:
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.Resources;
namespace MvcApplication.Controllers
{
public class BooksController : Controller
{
private BookDBContext db = new BookDBContext();
//
// GET: /Books/
public ViewResult Index(string sortOrder)
{
#region ViewBag Resources
#endregion
#region ViewBag Sort Params
// Define the sort orders - if the same link is
// clicked twice, reverse the direction from
// ascending to descending
ViewBag.TitleSortParam = (sortOrder == "Title")
? "Title desc" : "Title";
ViewBag.IsbnSortParam = (sortOrder == "Isbn")
? "Isbn desc" : "Isbn";
ViewBag.AuthorSortParam = (sortOrder == "Author")
? "Author desc" : "Author";
ViewBag.PriceSortParam = (sortOrder == "Price")
? "Price desc" : "Price";
ViewBag.PublishedSortParam =
(String.IsNullOrEmpty(sortOrder))
? "Published desc" : "";
// Default the sort order
if (String.IsNullOrEmpty(sortOrder))
{
sortOrder = "Published desc";
}
#endregion
var books = db.Books.OrderBy(sortOrder);
return View(books.ToList());
}
}
}
上邊的例子允許根據傳入的sortOrder 變量排序。上面的代碼是輕微的不安全,是為了證明
以最小的影響執行動態LINQ查詢的過程。由于這個變量可以通過URL傳入,為input數據添加一些驗證是十分重要的,這樣可以確保用戶沒法進行惡意行為。
另請參見
System.Linq.Expressions Namespace

浙公網安備 33010602011771號