正用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(*) 從 ({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屬性,並暴露出來.