- A+
分页SQL语句
完成上面的代码,分页效果已经出来了:
下面,我们使用第三方Express Profiler工具来检查EF生成的数据库分页SQL语句。
首先下载工具:
http://expressprofiler.codeplex.com/
打开Express Profiler,在Server文本框中输入(LocalDb)\MSSQLLocalDB,如果你使用的VS2013,这个字符串可能是:(LocalDb)\v11.0,点击绿色的启用按钮:
运行我们的示例,转到学生列表页面,然后清空Express Profiler中的全部显示,再点击第二页:
可以看到这里有3次SQL查询,这个和我们的心理预期是一样的:
- 第一次SQL查询:总记录数
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[Students] AS [Extent1]
) AS [GroupBy1]
go
对应的C#代码:
var students = db.Students as IQueryable<Student>;
var recordCount = students.Count();
- 第二次SQL查询:所学专业集合(去除重复)
SELECT
[Distinct1].[Major] AS [Major]
FROM ( SELECT DISTINCT
[Extent1].[Major] AS [Major]
FROM [dbo].[Students] AS [Extent1]
) AS [Distinct1]
go
对应的C#代码:
var majors = db.Students.OrderBy(m => m.Major).Select(m => m.Major).Distinct();
- 第三次SQL查询:分页数据
SELECT
[Extent1].[ID] AS [ID],
[Extent1].[Name] AS [Name],
[Extent1].[Gender] AS [Gender],
[Extent1].[Major] AS [Major],
[Extent1].[EntranceDate] AS [EntranceDate],
[Extent1].[Job] AS [Job]
FROM [dbo].[Students] AS [Extent1]
ORDER BY [Extent1].[Name] ASC
OFFSET 3 ROWS FETCH NEXT 3 ROWS ONLY
go
对应的C#代码:
return students.OrderBy(m => m.Name)
.Skip(pageIndex * PAGE_SIZE)
.Take(PAGE_SIZE).ToList();
这个查询顺序也和前面的EF代码的执行顺序一模一样,可以再回过头看下控制器Index方法。
同时处理表单检索和数据库分页
不过目前遇到点难题,我们希望实现如下两个功能:
- 点击分页链接时会发出HTTP POST请求,在请求参数中带上表单检索值。
- 表单检索时,在请求参数中带上当前所在的分页索引。
实现这两个功能才算完善,否则表单检索时如果丢失分页参数,就会回到第一页;而分页时如果丢失表单参数,就会清空表单输入框。
是不是开始怀念WebForms了,在WebForms中整个页面都被包含在一个表单中,因此回发时根本不需要考虑哪些参数后台需要。而MVC中这个就需要我们操心了,毕竟在灵活性的面前,便利性就会有所打折。
我们采取的办法是扩充前面的form标签,加入PageIndex隐藏字段,然后点击分页链接时提交表单即可:
using (Html.BeginForm("Index", "Students", FormMethod.Post, new { id = "searchForm" }))
{
@Html.AntiForgeryToken()
<p>
所学专业: @Html.DropDownList("Major",
ViewBag.MajorList as IEnumerable<SelectListItem>, "全部")
姓名: @Html.TextBox("Name")
<input type="hidden" id="PageIndex" name="PageIndex" value="0" />
<input type="button" id="searchButton" value="检索" />
</p>
}
注册JavaScript脚本来处理点击[检索]按钮和分页链接:
@section scripts {
<script>
function submitForm(pagenumber) {
pagenumber = parseInt(pagenumber, 10);
$('#PageIndex').val(pagenumber - 1);
$('#searchForm').submit();
}
$(function () {
$('#searchButton').click(function () {
submitForm($('#pagebar .currentpagenumber').text());
});
$('#pagebar .pagenumber').click(function () {
submitForm($(this).text());
});
});
</script>
}
现在看下效果,首先检索所学专业:
然后点击第二页,会发出一个POST请求:
可以看到本次请求,上面的用户输入和PageIndex都发送到了控制器处理方法:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(string Major, string Name, int PageIndex)
{
var students = db.Students as IQueryable<Student>;
if (!String.IsNullOrEmpty(Name))
{
students = students.Where(m => m.Name.Contains(Name));
}
if (!String.IsNullOrEmpty(Major))
{
students = students.Where(m => m.Major == Major);
}
var recordCount = students.Count();
var pageCount = GetPageCount(recordCount);
if (PageIndex >= pageCount && pageCount >= 1)
{
PageIndex = pageCount - 1;
}
students = students.OrderBy(m=>m.Name)
.Skip(PageIndex * PAGE_SIZE).Take(PAGE_SIZE);
ViewBag.PageIndex = PageIndex;
ViewBag.PageCount = pageCount;
ViewBag.MajorList = GetMajorList();
return View(students.ToList());
}
这里需要注意一点:先进行表单过滤,然后执行获取总记录数的查询,最后再获取分页数据。这个顺序不能变,因为表单过滤后总记录才能确定下来。
- 我的微信
- 这是我的微信扫一扫
- 我的微信公众号
- 我的微信公众号扫一扫