此文讲述mvc4+entityframework6+sqlserver2008环境下调用存储过程,实现分页。
1、分页存储过程代码如下:
分页原理用的row_number()和over()函数实现(没有用top、not in,因为性能低;sqlserver2012有新特性,用offset、fetch实现)。
这里支持多表查询分页。
SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].[Procedure_SpiltPage] ( @pageIndex INT =1, --页索引 @pageSize INT =10, --页大小 @tableName NVARCHAR(100), --表名 @fieldName NVARCHAR(200) ='*', --查询字段 @whereCondition NVARCHAR(800) ='1=1', --where条件 @orderCondition NVARCHAR(200), --order条件 @recordTotal INT OUTPUT, --输出记录总数 @pageCount INT OUTPUT --输出分页数 ) AS BEGIN DECLARE @sqlStr NVARCHAR(1000); SET NOCOUNT ON; --不返回计数 --返回记录总数 SET @sqlStr = 'SELECT @recordTotal = COUNT(*) FROM '+@tableName+' WHERE '+@whereCondition EXEC sp_executesql @sqlStr,N'@recordTotal INT OUTPUT',@recordTotal OUTPUT SET @pageCount=(@recordTotal+@pageSize-1)/@pageSize --查询列表 --如果是第一页 IF (@pageIndex<=1) BEGIN --N'表示强制转换为Unicode字符,不会乱码 SET @sqlStr=N'SELECT TOP '+CAST(@pageSize AS VARCHAR)+' '+@fieldName+' FROM '+@tableName+' WHERE '+@whereCondition+' ORDER BY '+@orderCondition END ELSE BEGIN --为了适应多表查询,下面把第一处@fieldName改为*,这里不查询全部字段,因为第二个@fieldName SET @sqlStr=N'SELECT * FROM (SELECT ROW_NUMBER() OVER(ORDER BY '+@orderCondition+') AS rownum, ' +@fieldName+' FROM '+@tableName+' WHERE '+@whereCondition+') AS myTable WHERE rownum BETWEEN ' +CAST(((@pageIndex-1)*@pageSize+1) AS NVARCHAR)+' AND '+CAST((@pageIndex*@pageSize) AS NVARCHAR) END EXEC (@sqlStr) SET NOCOUNT OFF; END GO
在数据库中测试,可以如下:
declare @total int declare @pageCount int exec Procedure_SpiltPage 1,15,'NewsInfo','*','1=1','PostTime desc',@total output,@pageCount output select @total as total,@pageCount as pageCounts
2、分页实现代码:
2.1、分页信息类如下:
namespace WebUI.PageinationService { /// <summary> /// 分页信息类 /// </summary> public class PageinationInfo { /// <summary> /// 页索引 /// </summary> public int PageIndex { get; set; } /// <summary> /// 页大小 /// </summary> public int PageSize { get; set; } /// <summary> /// 总数 /// </summary> public int TotalCount { get; set; } /// <summary> /// 总页数 /// </summary> public int TotalPages { get; set; } /// <summary> /// 表名 /// </summary> public string TableName { get; set; } /// <summary> /// 主键 /// </summary> public string KeyName { get; set; } /// <summary> /// 查询字段 /// </summary> public string FieldName { get; set; } /// <summary> /// where条件(不带'where') /// </summary> public string WhereCondition { get; set; } /// <summary> /// 排序条件,如:id desc ,或者:id desc,name asc /// </summary> public string OrderCondition { get; set; } } }
2.2、分页数据类(用以返回)
namespace WebUI.PageinationService { /// <summary> /// 分页数据类 /// 用以将分页集合和总数,总页数等打包一起返回 /// </summary> public class PageinationData { /// <summary> /// 总数 /// </summary> public int TotalCount { get; set; } /// <summary> /// 总页数 /// </summary> public int TotalPages { get; set; } /// <summary> /// 集合 /// </summary> public dynamic DataList { get; set; } } }
2.3、分页实现类:
namespace WebUI.PageinationService { /// <summary> /// 分页读取数据的实现类 /// </summary> public class PageinationImplement { //数据库上下文实例 private MyDbContext db; public PageinationImplement(MyDbContext dbContext) { this.db = dbContext; } /// <summary> /// 读取分页数据 /// </summary> /// <typeparam name="T">实体</typeparam> /// <param name="pageinationInfo">分页信息类</param> /// <returns>分页数据</returns> public PageinationData GetPageinationData<T>(PageinationInfo pageinationInfo) where T : class { dynamic result = null; try { #region SqlParameter参数 SqlParameter[] paras = new SqlParameter[8]; //页索引 paras[0] = new SqlParameter("pageIndex", DbType.Int32); paras[0].Value = pageinationInfo.PageIndex; //页大小 paras[1] = new SqlParameter("pageSize", DbType.Int32); paras[1].Value = pageinationInfo.PageSize; //表名 paras[2] = new SqlParameter("tableName", DbType.String); paras[2].Value = pageinationInfo.TableName; //查询字段 //EF仅支持返回返回某个表的全部字段,以便转换成对应的实体,无法支持返回部分字段的情况...??? paras[3] = new SqlParameter("fieldName", DbType.String); paras[3].Value = pageinationInfo.FieldName; //where条件 paras[4] = new SqlParameter("whereCondition", DbType.String); paras[4].Value = pageinationInfo.WhereCondition; //order条件 paras[5] = new SqlParameter("orderCondition", DbType.String); paras[5].Value = pageinationInfo.OrderCondition; //总数 paras[6] = new SqlParameter("totalCount", DbType.Int32); paras[6].Value = pageinationInfo.TotalCount; paras[6].Direction = ParameterDirection.Output; //总页数 paras[7] = new SqlParameter("totalPages", DbType.Int32); paras[7].Value = pageinationInfo.TotalPages; paras[7].Direction = ParameterDirection.Output; #endregion string sql = "Procedure_SpiltPage @pageIndex,@pageSize,@tableName,@fieldName,@whereCondition,@orderCondition,@totalCount output,@totalPages output"; var list = db.Database.SqlQuery<T>(sql, paras).ToList(); PageinationData data = new PageinationData(); data.TotalCount= (int)paras[6].Value; data.TotalPages= (int)paras[7].Value; data.DataList = list; result = data; } catch(Exception e) { throw; } return result; } } }
3、调用并返回数据:
PageinationImplement pageImpl = new PageinationImplement(db); PageinationInfo pageination = new PageinationInfo(); pageination.TableName = "NewsInfo"; pageination.PageIndex = 1; pageination.PageSize = 15; pageination.FieldName = "*"; pageination.OrderCondition = "PostTime desc"; pageination.WhereCondition = "Isdelete=0"; var data = pageImpl.GetPageinationData<NewsInfo>(pageination);
上面的new PageinationImplement(db)中的db是数据库上下文(DbContext实例),
上面的data里包括了分页列表,总记录数,分页页数 信息。
注:本来我执行存储过程,想只查询表的部分字段,结果会报错,暂时只能用*查询所有字段,
网上查说EF暂时仅支持返回返回某个表的全部字段,以便转换成对应的实体,无法支持返回部分字段的情况...
我能想到的方法就是自定义类,不用对应数据库的实体类。
不知道有没有其他方法可以实现,各位大神如果有方法的话,希望指教一下,谢谢!