Linq的延迟执行与MVC的分页
一条Linq语句,比如下面用于返回一个Dinner对象集合的查询
private NerdDinnerDataContext db = new NerdDinnerDataContext(); public IQueryable<Dinner> FindUpcomingDinners() { return from dinner in db.Dinners where dinner.EventDate > DateTime.Now orderby dinner.EventDate select dinner; }
这条“select”只有当它在的数据被访问或者迭代,又或者是ToList()方法被调用的时候,才会真正向数据库提交。该函数必须返回IQueryable<>类型,这样方便于我们应用点连接式Linq查询,来筛选结果集中的数据。
下面我们来看看如何利用它来实现MVC的分页机制。
我们按照设定的pageSize对数据进行服务端分页,实际上就是把结果集进行窗口筛选,然后回送给用户。
public ActionResult Index(int? page) { const int pageSize = 10; var upcomingDinners = this.dinnerRepository.FindUpcomingDinners(); var paginatedDinners = upcomingDinners.Skip((page ?? 0) * pageSize) .Take(pageSize) .ToList(); return View(paginatedDinners); }
从Model传递过来的结果集,通过Skip()和Take()两个动作,筛选出我们需要的那一页结果。注意这个查询是会被进行优化的。
要想访问某一页,需要在URL中以?参数的形式给出,比如/Dinners?page=1。但这样做并非SEO最优,我们还需要将其转换成常规URL,并且将参数嵌入进去。为此,MVC强大的路由功能就派上用场了。在Global.asax的后台代码中,加入这条路由的注册:
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 ); }
这样就可以将?参数转化为URL的一部分,至此,分页就搞定了。