分页
 如果dinners列表记录过多,为了让用户更方便浏览,我们需要实现分页显示,而不是一次显示大量的记录列表。
  Index() Action方法更新
 DinnersController类的Index() action方法代码如下:
         //
         // GET: /Dinners/
         public ActionResult Index()
         {
             var dinners = dinnerRepository.FindUpcomingDinners().ToList();
              return View("Index", dinners);
         }
  当用户请求/Dinners地址时,将返回所有即将来临的dinners列表,并在页面全部显示出来。
  理解IQueryable<T>
 IQueryable<T> 接口是.NET 3.5的LINQ中引入的,实现了强大的deferred execution,我们将利用这一特性实现分页功能。
 在DinnerRepository类中,FindUpcommingDinners() 方法将返回IQueryable<Dinner>对象。
         public IQueryable<Dinner> FindUpcomingDinners()
         {
             return from dinner in db.Dinners
                    where dinner.EventDate > DateTime.Now
                    orderby dinner.EventDate
                    select dinner;
         }
 FindUpcomingDinners() 方法返回的IQueryable<Dinner> 对象封装了使用LINQ to SQL从数据库中检索Dinner对象的查询。重要的是,该语句并不会对数据库执行查询,直到我们试图去访问或者遍历查询中的数据,或者我们调用ToList() 方法。调用FindUpcomingDinners() 方法在执行查询之前,可以选择添加额外的操作或过滤(chained operations/filters),当查询数据时,LINQ to SQL会聪明地对数据库执行组合查询。
 为了执行分页逻辑,我们更新了Index() action 方法,在调用ToList() 方法之前,对返回的IQueryable<Dinner>序列应用了附加的Skip 和Take操作符。
 //
 // GET: /Dinners/
 public ActionResult Index() {
 var upcomingDinners = dinnerRepository.FindUpcomingDinners();
 var paginatedDinners = upcomingDinners.Skip(10).Take(10).ToList();
 return View(paginatedDinners);
 }
 上述代码跳过数据库中前10条即将来临的Dinners记录,接着返回10条记录。LINQ to SQL聪明地构造了优化的SQL查询,在SQL 数据库端实现上述逻辑,仅仅返回我们想要的10条记录,使查询性能更加优化和可扩展性。
  在URL中添加page参数值
 我们将在URL中包含page参数值,标识用户请求的分页,而不是在代码中硬编码特定的页面范围。
  使用Querystring 参数值
 下面的代码演示如何使用更新Index() action 方法,支持querystring 参数,URL地址如/Dinners?page=2。
 // GET: /Dinners/
 // /Dinners?page=2
 public ActionResult Index(int? page) {
 const int pageSize = 10;
 var upcomingDinners = dinnerRepository.FindUpcomingDinners();
 var paginatedDinners = upcomingDinners.Skip((page ?? 0) * pageSize)
 .Take(pageSize)
 .ToList();
  return View(paginatedDinners);
 }
  上述Index() 方法有一个参数page,该参数定义为nullable 整型。/Dinners?page=2 地址表示2将传递为参数值。/Dinners 地址(没有querystring 参数)将传入一个空值。
 我们通过page乘以页面记录数(page size,本范例为10)来决定需要跳过的dinners记录条数。同时,我们使用了C#操作符(??),该操作在处理nullable类型时,非常有用。如果page参数为空(null),上述代码将对page赋值为0。
  使用嵌入的URL参数值
 除了了querystring外,另外的一个办法是嵌入page参数到实际的URL中,如/Dinners/Page/2 或者/Dinners/2。ASP.NET MVC包含了一个强大的URL路由引擎,可以轻松支持上述场景。
 我们可以注册定制的路由规则,映射任何进来的URL或URL格式到任何Controller控制器类和Action方法。可以通过打开项目中Global.asax文件来实现。
 使用MapRoute() 辅助方法,注册一个新的映射规则,像第一次调用routes.MapRoute()方法:
         public static void RegisterRoutes(RouteCollection routes)
         {
             routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
              routes.MapRoute(
                 "UpcomingDinners",
                 "Dinners/Page/{page}",
                 new { controller = "Dinners", action = "Index" }
             );
              routes.MapRoute(
                 "Default",                                              // Route name
                 "{controller}/{action}/{id}",                           // URL with parameters
                 new { controller = "Home", action = "Index", id = "" } // Parameter defaults
             );
          }
  在上述代码中,我们注册了一个新的路由规则 – UpcommingDinners,URL格式为/Dinners/Page/{page},其中{page} 是嵌入在URL的参数。MapRoute() 方法将符合上述URL格式的请求映射到DinnersController类的Index() action 方法。
  我们使用与Querystring方案中完全相同的Index() 方法,处理page参数将来自于URL,而不是querystring:
         //
         // GET: /Dinners/
         // /Dinners/Page/2
         public ActionResult Index(int? page)
         {
             const int pageSize = 10;
             var upcomingDinners = dinnerRepository.FindUpcomingDinners();
             var paginatedDinners = upcomingDinners.Skip((page ?? 0) * pageSize)
             .Take(pageSize)
             .ToList();
             return View(paginatedDinners);
         }
  现在访问/Dinners URL时,将返回前10条记录,而不是全部记录了。
 
 
接下来访问/Dinners/Page/1 URL时,将看到下一页的Dinners记录。
 
 
添加页面导航界面
实现页面分页的最后一步是在视图模板中添加上一页、下一页的导航界面,方便用户在页面之间切换。
 为了正确实现这一步,我们需要知道数据库中Dinners的记录数和需要分为多少页。接着,我们计算当前请求的页面是开始页或是最后页,并正确显示或隐藏上一页和下一页的导航链接。我们将在Index() action 方法中实现这一逻辑。另一选择是,我们在项目中添加一个辅助类,封装这一逻辑,实现更多地方的重用。
  下面是一个简单PaginatedList 辅助类,继承.NET Framework 内置的List<T>集合类。它实现了一个可重用的集合类,用来在任何IQueryable序列中实现分页。在NerdDinner范例程序中,用来对IQueryable<Dinner> 结果集进行分页,但是它也可用于其他应用程序中对IQueryable<Product>或IQueryable<Customer>结果集进行分页。
     public class PaginatedList<T> : List<T>
     {
         public int PageIndex { get; private set; }
         public int PageSize { get; private set; }
         public int TotalCount { get; private set; }
         public int TotalPages { get; private set; }
          public PaginatedList(IQueryable<T> source, int pageIndex, int pageSize)
         {
             PageIndex = pageIndex;
             PageSize = pageSize;
             TotalCount = source.Count();
             TotalPages = (int)Math.Ceiling(TotalCount / (double)PageSize);
             this.AddRange(source.Skip(PageIndex * PageSize).Take(PageSize));
         }
         public bool HasPreviousPage
         {
             get
             {
                 return (PageIndex > 0);
             }
         }
         public bool HasNextPage
         {
             get
             {
                 return (PageIndex + 1 < TotalPages);
             }
         }
     }
  上述类公开的4个属性,PageIndex、PageSize、TotalCount 和 TotalPages等等,另外公开了2个辅助属性:HasPreviousPage和HasNextPage,这2个属性分别表示是否页面数据在集合的开始页或者结束页。上述代码将引起执行2次SQL 查询,第一次检索Dinner Objects总记录数(不返回对象,仅仅是执行SELECT COUNT语句,返回一个整型值),第二次检索数据库,返回当前页需要的数据列表。
  接着,我们更新DinnersController.Index() 辅助方法,从DinnerRepository.FindUpcomingDinners() 结果集中创建一个PaginatedList<Dinner> 对象,并传递给视图模板。
         // GET: /Dinners/
         // /Dinners/Page/2
         public ActionResult Index(int? page)
         {
             const int pageSize = 10;
             var upcomingDinners = dinnerRepository.FindUpcomingDinners();
             var paginatedDinners = new PaginatedList<Dinner>(upcomingDinners, page ?? 0, pageSize);
              return View(paginatedDinners);
         }
  接着更新\Views\Dinners\Index.aspx 视图模板,从继承ViewPage<IEnumerable<Dinner>>更新为ViewPage<NerdDinner.Helpers.PaginatedList<Dinner>>,然后添加如下代码到视图模板的底部,显示或隐藏上一页和下一页的导航链接:
     <% if (Model.HasPreviousPage)
        { %>
     <%= Html.RouteLink("上一页","UpcomingDinners",new { page=(Model.PageIndex-1) }) %>
     <% } %>
     <% if (Model.HasNextPage)
        { %>
     <%= Html.RouteLink("下一页","UpcomingDinners",new { page = (Model.PageIndex + 1) })%>
     <% } %>
  上述代码使用Html.RouteLink() 辅助方法生成HTML超链接,这一方法与我们前面使用的Html.ActionLink() 辅助方法比较相似。区别是生成URL地址时,使用Global.asax文件中设置的路由规则。确保生成的URL和Index() Action方法有相同的格式:/Dinners/Page/{page} – 其中{page} 参数值基于当前页的序号来提供。
 
 现在,我们访问NerdDinner应用程序时,每次将展示10条Dinners记录。
 
 
在页脚也提供了上一页和下一页的导航链接,实现页面跳转。
 来自西北的狼!