天天看點

分頁管理器實作

    在DataGrid的web版控件中提供了自動分頁的功能,但是我從來沒用過它,因為它實作的分頁隻是一種假相。我們為什麼需要分頁?那是因為符合條件的記錄可能很多,如果一次讀取所有的記錄,不僅延長擷取資料的時間,而且也極度浪費記憶體。而分頁的存在的主要目的正是為了解決這兩個問題(當然,也不排除為了UI美觀的需要而使用分頁的)。而web版的DataGrid是怎樣實作分頁的了?它并沒有打算解決上述兩個問題,而還是一次讀取所有的資料,然後以分頁的樣子表現出來。這是對效率和記憶體的極大損害!

    于是我自己實作了分頁管理器IPaginationManager ,IPaginationManager 每次從資料庫中讀取指定的任意一頁,并且可以緩存指定數量的page。這個分頁管理器的主要特點是:

(1)支援随機跳轉。這是通過嵌套Select語句實作的。

(2)支援緩存。通過EnterpriseServerBase.DataStructure.FixCacher進行支援。

    先來看看IPaginationManager接口的定義:

    public interface IPaginationManager

    {

        void      Initialize(DataPaginationParas paras) ;

        void      Initialize(IDBAccesser accesser ,int page_Size ,string whereStr ,string[] fields) ;//如果選擇所有列,fields可傳null

        DataTable GetPage(int index) ;  //取出第index頁

        DataTable CurrentPage() ;

        DataTable PrePage() ;

        DataTable NextPage() ;

        int          PageCount{get ;}

        int       CacherSize{get; set; }

    }

    這個接口定義中,最主要的是GetPage()方法,實作了這個方法,其它的三個擷取頁面的方法CurrentPage、PrePage、NextPage也就非常容易了。另外,CacherSize屬性可以讓我們指定緩存頁面的數量。如果不需要緩存,則設定其值<=0,如果需要無限緩存,則值為Int.MaxValue。

    IPaginationManager接口中的第二個Initialize方法,你不要關心,它是給XCodeFactory生成的資料層使用了,我們來看看第一個Initialize方法的參數類型DataPaginationParas的定義:

    public class DataPaginationParas

        public int      PageSize = 10 ;        

        public string[] Fields = {"*"}; //要搜尋出的列,"*"表示所有列

        public string   ConnectString ;

        public string   TableName ; 

        public string   WhereStr ;      //搜尋條件的where字句

        public DataPaginationParas(string connStr ,string tableName ,string whereStr)

        {

            this.ConnectString = connStr ;

            this.TableName       = tableName ;

            this.WhereStr      = whereStr ;

        }        

        #region GetFiedString

        public string GetFiedString()

            if(this.Fields == null) 

            {

                this.Fields = new string[] {"*"} ;

            }

            string fieldStrs = "" ;

            for(int i=0 ;i<this.Fields.Length ;i++)

                fieldStrs += " " + this.Fields[i] ;

                if(i != (this.Fields.Length -1))

                {

                    fieldStrs += " , " ;

                }

                else

                    fieldStrs += " " ;

            return fieldStrs ;

        }

        #endregion

    DataPaginationParas.GetFiedString用于把要搜尋的列形成字元串以便嵌入到SQL語句中。DataPaginationParas中的其它字段的意思都很明顯。

    現在來看看分頁管理器的實作了:

    public class PaginationManager :IPaginationManager

        private DataPaginationParas   theParas ;

        private IADOBase              adoBase ;            

        private DataTable   curPage      = null ;

        private int         itemCount    = 0 ;

        private int         pageCount    = -1 ;        

        private int         curPageIndex = -1 ;

        private FixCacher   fixCacher    = null ;

        private string      fieldStrs    = "" ;

        /// <summary>

        /// cacheSize 小于等于0 -- 表示不緩存 ,Int.MaxValue -- 緩存所有

        /// </summary>        

        public PaginationManager(int cacheSize)

            if(cacheSize == int.MaxValue)

                this.fixCacher = new FixCacher() ;

            else if(cacheSize >0)

                this.fixCacher = new FixCacher(cacheSize) ;

            else

                this.fixCacher = null ;

        }    

        public PaginationManager()

        #region IDataPaginationManager 成員

        public int CacherSize

            get

                if(this.fixCacher == null)

                    return 0 ;

                return this.fixCacher.Size ;

            set

                    this.fixCacher = new FixCacher(value) ;

                    this.fixCacher.Size = value ;

        public int PageCount

                if(this.pageCount == -1)

                    string selCountStr = string.Format("Select count(*) from {0} {1}" ,this.theParas.TableName ,this.theParas.WhereStr) ;

                    DataSet ds = this.adoBase.DoQuery(selCountStr) ;

                    this.itemCount = int.Parse(ds.Tables[0].Rows[0][0].ToString()) ;

                    this.pageCount = this.itemCount/this.theParas.PageSize ;

                    if((this.itemCount%this.theParas.PageSize > 0))

                    {

                        ++ this.pageCount ;

                    }

                return this.pageCount ;

        /// GetPage 取出指定的一頁

        public DataTable GetPage(int index)

            if(index == this.curPageIndex)

                return this.curPage ;

            if((index < 0) || (index > (this.PageCount-1)))

                return null;

            DataTable dt = this.GetCachedObject(index) ;

            if(dt == null)

                string selectStr = this.ConstrutSelectStr(index) ;

                DataSet ds = this.adoBase.DoQuery(selectStr) ;

                dt = ds.Tables[0] ;

                this.CacheObject(index ,dt) ;

            this.curPage      = dt ;

            this.curPageIndex = index ;

            return this.curPage ;

        private DataTable GetCachedObject(int index)

            if(this.fixCacher == null)

                return null ;

            return (DataTable)this.fixCacher[index] ;

        private void CacheObject(int index ,DataTable page)

            if(this.fixCacher != null)

                this.fixCacher.PutIn(index ,page) ;

        public DataTable CurrentPage()

        public DataTable PrePage()

            return this.GetPage((--this.curPageIndex)) ;

        public DataTable NextPage()

            return this.GetPage((++this.curPageIndex)) ;

        private string ConstrutSelectStr(int pageIndex)

            if(pageIndex == 0)

                return string.Format("Select top {0} {1} from {2} {3} ORDER BY ID" ,this.theParas.PageSize ,this.fieldStrs ,this.theParas.TableName ,this.theParas.WhereStr) ;

            int innerCount     = this.itemCount - this.theParas.PageSize*pageIndex ;

            string innerSelStr = string.Format("Select top {0} {1} from {2} {3} ORDER BY ID DESC " ,innerCount , this.fieldStrs ,this.theParas.TableName ,this.theParas.WhereStr) ;

            string outerSelStr = string.Format("Select top {0} * from ({1}) DERIVEDTBL ORDER BY ID" ,this.theParas.PageSize ,innerSelStr) ;

            return outerSelStr ;

        #region Initialize

        public void Initialize(IDBAccesser accesser, int page_Size, string whereStr, string[] fields)

            this.theParas = new DataPaginationParas(accesser.ConnectString ,accesser.DbTableName ,whereStr) ;

            this.theParas.Fields = fields ;

            this.theParas.PageSize = page_Size ;

            this.fieldStrs = this.theParas.GetFiedString() ;    

            this.adoBase = new SqlADOBase(this.theParas.ConnectString) ;

        public void Initialize(DataPaginationParas paras)

            this.theParas = paras ;

    了解這個類的實作,可以從GetPage(int index)方法入手,另外私有方法ConstrutSelectStr()的實作說明了如何使用嵌套sql語句進行随機分頁搜尋。

    最後,關于分頁管理器,需要指出的是,搜尋對應的表必須有一個名為"ID"的主鍵--這是唯一的要求。另外,分頁管理器實作用到的資料通路低階封裝IADOBase定義于EnterpriseServerBase類庫中。

    使用分頁管理器是很簡單的,加上UI界面後,隻要把傳回的DataTable綁定到DataGrid就可以了:)