[小把戲] 之IBatis.Net系統分頁問題的解決


  本文想解決園子里大家都關心的Ibatis.Net分頁的實現問題。其實我也找了Ibatis.Net分頁的解決方案,園子里有一些,奈何沒有發現我想要的方式,大都的策略是調用兩次SQL Statement,第一次,根據條件查詢總記錄條數,第二次,根據條件查詢從第N行到M行的數據集合,不是這種不能滿足條件,恰恰相反,這種寫法,完全可以滿足現有項目的需求,也很具備SQL調優空間,但有個的弊端,是通過一個查詢寫幾遍。很難復用。感覺很是別扭,我看過在查詢較多的系統里,到處充斥這分頁的SQL語句,另外一點,本來我們碼農們只要關心實現獲取業務數據就行了,每次在實現功能的基礎上,還要再加上分頁的SQL語句,使原本的可能就復雜的語句,變得更加復雜和難以理解。

  為此,我特地Reflect看了Ibatis.Net的源碼。根據他的處理邏輯擴展了SqlMapper的接口,增加 IList<T> QueryForListWithPage<T>這種功能。本想通過注入的方式實現的,看過Java的筒子們曾用注入的方式搞定過。可惜Ibatis.Net沒有發現這種方式(或許我才疏學淺,沒有找到)。貌似MyBatis已經支持。但沒有實踐過。本文代碼只針對Ibatis 1.62版本和使用MSSQL數據庫。如果感覺此思路還不錯,我的源碼是共享滴,完全可以下載源碼,改造成你想要的其它方式。

  至於分頁的SQL,個人偏好row_number這種方法,其它的如分頁存儲過程,TOP方式就不費筆墨了。

  話多無益。直接上碼  

 //獲取學生列表(使用配置GetStudentList的sql,按照id升序排序獲取從第八十個到第一百學生)
 var list = mapper.QueryForListWithPage<T>("GetStudentList", paras, "id asc", 80, 100, ref count);

   那么具體實現怎么寫呢,我采用c#的擴展方法,擴展了Ibatis.Net標配的SqlMapper功能,看起來類似Ibatis.Net原生態的功能,但又沒有破壞Ibatis源碼,這種插件式,不會給原有的Ibatis引入任何的Bug. 

    public static class SqlMapperExtension
    {
        private const string PageSql =
            "with cte as( select id0=row_number() over(order by {0}),* from  ({1}) as cte1) select * from cte where id0 between @beginNo and @endNo";

        private const string CountSql = "select count(*) {0}";

        /// <summary>
        /// 查詢分頁
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="mapper">mapper</param>
        /// <param name="tag">SQL Statement的id</param>
        /// <param name="paramObject">參數</param>
        /// <param name="orderby">查詢條件,必須確保數據庫中有這一列</param>
        /// <param name="beginNo">開始行數</param>
        /// <param name="endNo">結束行數</param>
        /// <param name="totalCount">總條數</param>
        /// <returns>查詢結果</returns>
        public static IList<T> QueryForListWithPage<T>(this ISqlMapper mapper, string tag, object paramObject,string orderby, int beginNo, int endNo, ref int totalCount)
        {
            bool flag = false;
            ISqlMapSession sqlMapSession = mapper.LocalSession;
            if (sqlMapSession == null)
            {
                sqlMapSession = mapper.CreateSqlMapSession();
                flag = true;
            }
            try
            {
                IMappedStatement mappedStatement = mapper.GetMappedStatement(tag);
                IStatement statement = mappedStatement.Statement;
                RequestScope request = statement.Sql.GetRequestScope(mappedStatement, paramObject, sqlMapSession);
                string statementsql = request.PreparedStatement.PreparedSql;
                string cmdPageSql = string.Format(PageSql, orderby, statementsql);
                string cmdCountSql = string.Format(CountSql,statementsql.Substring(statementsql.ToLower().IndexOf("from")));

                request.PreparedStatement.PreparedSql = cmdPageSql;
                request.IDbCommand = new DbCommandDecorator(sqlMapSession.CreateCommand(statement.CommandType), request);
                ApplyParameterMap(sqlMapSession, request.IDbCommand, request, statement, paramObject);
                totalCount = GetCount(request, sqlMapSession, cmdCountSql);
                request.IDbCommand.CommandText = request.PreparedStatement.PreparedSql;
                AddCommandParameters(beginNo, endNo, request);
                IList<T> result = RunQueryForList<T>(statement, request, sqlMapSession, paramObject, null, null);
                return result;
            }
            finally
            {
                if (flag)
                {
                    sqlMapSession.CloseConnection();
                }
            }
        }
    }

   園友們若想直接拿來使用,可以下載附件文件,在引用Ibatis.Net的dll同時,在工程里再增加SqlMapperExtension這個類文件,就可以方便調用了。此方法在Ibatis.Net1.62版本下,使用MSSQL,已經通過測試驗證。OK,如果你不想分頁功能,那么就還是使用下面的方式。  

         var listall = mapper.QueryForList<T>(statementName, paras);

  這樣你只需要在sqlmapper的xml里寫一個SQL語句,獲取全部記錄和獲取分頁記錄(含有總條數)兩件事就都可以搞定.

  覺得好的話,別忘了頂一下哦,呵呵.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM