EFCore-分页查询
EFCore-分页查询
在之前我们了解到,在IQuryable和IEnumerable中,where的方法是在不同的接口实现的
IEnumerable是在内存中过滤(客户端评估)
IQuryable是把操作翻译成SQL语句(服务端评估)
所以在实际开发中,我们不会使用到IEnumerable接口来接受数据库查询的数据
延迟执行
IQuryable支持延迟执行,即不立即执行
它只是一个“可以放到数据库服务器去执行的查询”,他没有立即执行,只是“可以被执行”而已
对于IQueryable接口调用非终结方法的时候不会执行查询,调用终结方法的时候会立即执行查询
这样延迟查询的好处,可以动态拼接查询条件,根据不同的查询条件编译不同的SQL语句
因为这种延迟查询的缘故,所以不能将IQueryable对象传到DbContext销毁外执行
非终结方法 | 终结方法 |
---|---|
GroupBy() | 遍历 |
OrderBy() | ToArray() |
Include() | ToList() |
Skip() | Min()/Max() |
Take() | Count() |
一个方法的返回值类型如果是IQueryable类型,则为非终结方法,反之则为终结方法
需要注意的是:非终结方法没有异步方法,而终结方法普遍都存在异步方法
但一般来讲,遍历和ToList,ToArray方法没必要使用异步方法
对象复用
通过非终结方法生成的IQuryable对象可以通过不同的终结方法来编译成不同的SQL语句
分页查询
通过对IQuryable的复用和非终结方法Skip()以及Take()来实现分页查询功能
/// <summary>
/// 此方法用于返回一页数据和总页数
/// </summary>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
static void PrintPage(int pageIndex, int pageSize)
{
using (var dbContext = new DBContext())
{
// 这时,程序还未向数据库发送SQL
var queryable = dbContext.Articles.Select(a => a);
// 跳过 当前页码-1 *每页条数(跳过的数据总条数)再拿一页数据
var data = queryable.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
// queryable的复用,在用一次计算总条数
long count = queryable.LongCount();
// 计算总页数 使用Math.Ceiling方法向上取整
long pageCount = (long)Math.Ceiling(count / (double)pageSize);
}
}
至此,拿到分页五大件
IQuryable底层
EFCore可以理解为是针对与ADO.NET的封装
在ADO.NET中,存在DataReader和DataTable对象
- DataReader:分批从数据库读取数据,内存占用小,DB链接占用时间长
- DataTable:把所有数据一次性的从数据库中加载到内存中,内存占用大,DB占用链接短
而IQueryable则实现了DataReader,节省了客户端内存,如果处理的慢,就会长时间占用数据库连接
如果想要一次性的将数据加载到内存,则使用IQueryable的ToArray()、ToArrayAsync()、ToList()、ToListAsync()方法
而因为DataReader的特性,是不允许多个DataReader同时执行的,所以不能对IQueryable进行嵌套遍历