前段时间开发报表,采用了 ReportViewer + RDLC , 开发整理如下.
分页思路MS 的DataGrid ,GridView,和 ReportViewer 分页机制差不多,都需要绑定全部数据,MS控件自动处理分页。 只是ReportViewer 是按页面布局分页的,而不是按数据条数。绑定全部数据的方式会无谓的增加服务器压力,尤其是数据计算和表关联多的情况下。为了减轻服务器压力,我们采用数据分页,数据传到应用服务器端后,再加工一下(插入空数据),做也可分页数据源。
如果数据库有 100 条数据,每页10条数据,那存储过程返回10条数据后,还需要再插入90条数据。当数据大的时候,插入的数据也很多。有没有插入数据再少一点的办法呢?
当然是有了,没有就不写了。。先提两个概念:维度和指标.
维度: 是指公司,项目,区域等要分析的对象.
指标: 是指针对维度进行计算的结果
1. 先对维度进行分页.
2.针对分页结果,有针对性的进行指标计算 ,可以把每个计算列,做成函数,方便调用,同时,也方便维护和测试。
实现方案方案是把页码做成分组,这样再插入的时候,就只插入 Celling( 90 ÷ 10 ) 条的空分组数据即可。 插入的数据少了 n 倍。
存存过程示例代码:
CREATE proc [dbo].[R_ANALYSIS] ( @Query varchar(50)= ', --查询条件 @PageIndex int = 1 , --从1开始 @PageSize int = 50 , --每页条数,传入 0 ) begin --计算 @RowCount set @PageCount = ceiling( @RowCount *1.0 / @PageSize) ;end else begin set @PageCount = 1 end
end
所需要的两个程序加工函数:
public static IEnumerable ReportWrap(this IEnumerable Source, int CurrentPageIndex, int PageCount) where T : IReportModel, new() { if (PageCount < 2) { foreach (var item in Source) { yield return item; } yield break; }Func CreateEmptyObj = (CurrentIndex) => { T retVal = new T();
retVal.SysPageIndex = CurrentIndex;
return retVal; };
for (int i = 0; i < CurrentPageIndex; i++) { yield return CreateEmptyObj(i + 1); }
foreach (var item in Source) { item.SysPageIndex = CurrentPageIndex + 1; yield return item; }
for (int i = CurrentPageIndex + 1; i < PageCount; i++) { yield return CreateEmptyObj(i + 1); } }
public static DataTable ReportWrap(this DataTable Source, int CurrentPageIndex, int PageCount){ if (PageCount { DataRow retVal = Source.NewRow();
retVal["SysPageIndex"] = CurrentIndex;
return retVal; };
for (int i = 0; i < CurrentPageIndex; i++) { Source.Rows.InsertAt(CreateEmptyObj(i + 1), 0); }
for (int i = CurrentPageIndex + 1; i < PageCount; i++) { Source.Rows.Add(CreateEmptyObj(i + 1)); }
return Source;}
程序调用函数代码,很简单:
DataTable dt = db.Exec_SP_DataTable("sp_Report_ModuleVisitStatisView", pars);pageCount = Convert.ToInt32(pars[6].Value);dt.ReportWrap(pageIndex -1 , pageCount);之后,再把 DataTable 转成 实体列表。方便RDLC数据绑定。
另注:
上面的 IReportModel , 是一个只包含 SysPageIndex 属性的接口. 它约束了报表返回的Model 必须继承自 IReportModel 且必须拥有 无参构造函数.
1. 无参构造函数的作用是 初始化空对象. 比如: 字符串类型的,要设置为 string.Empty . 数值类型要设置为 0.
2.接口是约束Model 必须具有 SysPageIndex 属性用于页码值.
报表RDLC 的设置:
绑定数据源,添加父组,选 SysPageIndex。在该列的属性上设置: Hidden = True , Width = 0cm。即隐藏该列。后端绑定代码:
ReportDataSource data = new ReportDataSource("LogSource", MyBiz.GetLogReportData("query", pageIndex, pageSize, out pageCount));this.ReportViewer1.LocalReport.LoadReportDefinition(new FileStream(Server.MapPath("~/Admin/Report/Log.rdlc")));this.ReportViewer1.LocalReport.DataSources.Clear();this.ReportViewer1.LocalReport.DataSources.Add(data);
至此,分页就做好了.