CSLA.Net在Web项目中使用SQL2005的分页
正用CSLA.NET做一个Web的项目, 发现CSLA的模型在开发Web时, 不是很适合中国国情.
他的一系列模版, 都是基于主从表单的考虑, 比如"采购单", 这样有单头, 有明细行的情况, 这在WinForm下很棒.
但Web下, 大部分对象都单独用一个表单进行编辑, 所以感觉有些别扭.
我的理解还不深入, 还不断学习中, 整个框架让我受益很多. 废话完了, 进入正题.
要在CSLA模型中方便的使用Sql2005的分页, 我们要做四步.
第一步: 实现一个PagingCriteria, 用来传递分页参数.
[Serializable()] public class PagingCriteria<T> : CriteriaBase { #region Filed public IDictionary ParamDic { get; private set; } public string SortExpression { get; private set; } public string DefaultOrder { get; private set; } public int StartRowIndex { get; private set; } public int MaximumRows { get; private set; } #endregion protected PagingCriteria(){ } public PagingCriteria(IDictionary paramDic, int startRowIndex, int maximumRows, string sortExpression, string defaultOrder) : base(typeof(T)) { ParamDic = paramDic; SortExpression = sortExpression; DefaultOrder = defaultOrder; StartRowIndex = startRowIndex; MaximumRows = maximumRows; } }
第二步: 实现PagingWrapper, 将普通的Sql语句封装成可分页的语句.
public static class PagingWrapper { private const string SQLTEMPLATE = @"With TargetTable AS(select ROW_NUMBER() OVER (order by Temp.{1})as RowNumber,Temp.* from ({0}) as Temp) select * from TargetTable WHERE RowNumber between {2} and {3};Select count(*) from ({0}) Temp"; public static string Wrap(string sqlQuery, string SortExpression, int startRowIndex, int maximumRows) { if (string.IsNullOrEmpty(SortExpression)) throw new Exception("未指定排序列."); return string.Format(SQLTEMPLATE, sqlQuery, SortExpression, startRowIndex +1, startRowIndex + maximumRows); } public static string Wrap<T>(string sqlQuery, PagingCriteria<T> criteria) { string order = (string.IsNullOrEmpty(criteria.SortExpression)) ? criteria.DefaultOrder : criteria.SortExpression; return Wrap(sqlQuery, order, criteria.StartRowIndex, criteria.MaximumRows); } }
第三部: 在集合对象中调用.这里是RoleList.
using (SqlCommand cm = cn.CreateCommand()) { cm.CommandType = CommandType.Text; string sql = "SELECT * FROM Roles"; cm.CommandText = PagingWrapper.Wrap(sql, criteria); using (SafeDataReader dr = new SafeDataReader(cm.ExecuteReader())) { while (dr.Read()) Add(Role.FillRole(dr)); dr.NextResult(); dr.Read(); TotalRowCount = dr.GetInt32(0); } }
CommandText就是调用用Wrapper返回的. TotalRowCount属性是Csla.Core.IReportTotalRowCount接口的实现.
第四步: 在页面上用数据源控件, 绑定Gridview并实现分页:
private int totalCount = 0; protected void CslaDs_SelectObject(object sender, Csla.Web.SelectObjectArgs e) { BLL.Security.RoleList list = BLL.Security.RoleList.PagingRoleList(null, e.SortExpression, e.StartRowIndex, e.MaximumRows); e.BusinessObject = list; totalCount = list.TotalRowCount; } protected void gvlist_RowDataBound(object sender, GridViewRowEventArgs e) { if (e.Row.RowType == DataControlRowType.Pager) { ((Label)e.Row.FindControl("lblTotal")).Text = totalCount.ToString(); } }
public static RoleList PagingRoleList(IDictionary paramDic, string SortExpression, int startRowIndex, int maximumRows) { return DataPortal.Fetch<RoleList>(new PagingCriteria<RoleList>(paramDic, startRowIndex, maximumRows, SortExpression, "ID")); }
页面Gridview分页部分:
<PagerTemplate> <br /> 共<asp:Label ID="lblTotal" runat="server" ></asp:Label>行 <asp:Label ID="lblPage" runat="server" Text='<%# "第" + (((GridView)Container.NamingContainer).PageIndex + 1) + "页/共" + (((GridView)Container.NamingContainer).PageCount) + "页" %> '></asp:Label> <asp:LinkButton ID="lbnFirst" runat="Server" Text="首页" Enabled='<%# ((GridView)Container.NamingContainer).PageIndex != 0 %>' CommandName="Page" CommandArgument="First"></asp:LinkButton> <asp:LinkButton ID="lbnPrev" runat="server" Text="上一页" Enabled='<%# ((GridView)Container.NamingContainer).PageIndex != 0 %>' CommandName="Page" CommandArgument="Prev"></asp:LinkButton> <asp:LinkButton ID="lbnNext" runat="Server" Text="下一页" Enabled='<%# ((GridView)Container.NamingContainer).PageIndex != (((GridView)Container.NamingContainer).PageCount - 1) %>' CommandName="Page" CommandArgument="Next"></asp:LinkButton> <asp:LinkButton ID="lbnLast" runat="Server" Text="尾页" Enabled='<%# ((GridView)Container.NamingContainer).PageIndex != (((GridView)Container.NamingContainer).PageCount - 1) %>' CommandName="Page" CommandArgument="Last"></asp:LinkButton> <br /> </PagerTemplate>
这里要说明的是, 总行数是通过list.TotalRowCount属性来获得的. 所以RoleList 需要实现Csla.Core.IReportTotalRowCount接口.
你可能会问, 为什么不在Gridview,PagerTemplate中直接写入总行数, 其实是因为Gridview并未暴露这个属性,System.Web.UI.DataSourceSelectArguments对象,
在获取数据后, 会将总行数返回给Gridview内部, 但Gridview内部会在私有方法中,构一个局部的PagedDataSourse, 将总行数记录在里面, 外部无法获取, 通过反射也不行.
所以最简单的方式, 就是先记下来, 然后在RowDataBound事件中把它写上去. 如果你要求完美, 可以自己封装一个Gridview加上这个TotalRowCount属性,并暴露出来.
如果有更好的办法, 请告诉我, 不要保留:)