基于Dapper實(shí)現(xiàn)分頁(yè)效果 支持篩選、排序、結(jié)果集總數(shù)等
簡(jiǎn)介
之前事先搜索了下博客園上關(guān)于Dapper分頁(yè)的實(shí)現(xiàn),有是有,但要么是基于存儲(chǔ)過(guò)程,要么支持分頁(yè),而不支持排序,或者搜索條件不是那么容易維護(hù)。
代碼
首先先上代碼: https://github.com/jinweijie/Dapper.PagingSample
方法定義
以下是我的一個(gè)分頁(yè)的實(shí)現(xiàn),雖然不是泛型(因?yàn)榭紤]到where條件以及sql語(yǔ)句的搭配),但是應(yīng)該可以算是比較通用的了,方法定義如下:
public Tuple<IEnumerable<Log>, int> Find(LogSearchCriteria criteria , int pageIndex , int pageSize , string[] asc , string[] desc);
以上函數(shù)定義是一個(gè)查詢Log的示例,返回結(jié)果中,Tuple的第一個(gè)值是結(jié)果集,第二個(gè)值是總行數(shù)(例如,總共有100條記錄,每頁(yè)10條,當(dāng)前第一頁(yè),那么第一個(gè)值是10條記錄,第二個(gè)值是100)
在示例項(xiàng)目中,我用兩種方法實(shí)現(xiàn)了分頁(yè):
1. 第一種是基于2此查詢,第一次得到總數(shù),第二次查詢得到結(jié)果集。
2. 第二種是基于1此查詢,用了SqlServer 的Offest/Fetch,所以只支持Sql Server 2012+,所以大家根據(jù)自己用的Sql Server版本選擇不同的實(shí)現(xiàn),這里當(dāng)然是第二種實(shí)現(xiàn)效率更高一點(diǎn)。
運(yùn)行示例
1. 將Github的Repo下載或者Clone到本地以后,到Database目錄下,解壓縮Database.7z
2. Attach到Sql Server上。默認(rèn)我使用Sql Server LocalDB,連接字符串是 Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=DapperPagingSample;integrated security=True; 如果你用的不是LocalDB,請(qǐng)酌情修改App.Config的連接字符串。
3. Ctrl+F5運(yùn)行程序,示例項(xiàng)目里,我用了一個(gè)簡(jiǎn)單的WinForm程序,但應(yīng)該可以比較好的演示分頁(yè)效果。
多表支持
增加了示例,支持多表查詢,例如有兩個(gè)Log表,Level表,Log的LevelId字段引用Level的Id字段,通過(guò)以下的查詢,可以實(shí)現(xiàn)多表查詢的分頁(yè),排序,過(guò)濾:
首先是通過(guò)兩次查詢的示例(基本支持所有版本Sql Server):
public Tuple<IEnumerable<Log>, int> Find(LogSearchCriteria criteria , int pageIndex , int pageSize , string[] asc , string[] desc) { using (IDbConnection connection = base.OpenConnection()) { const string countQuery = @"SELECT COUNT(1) FROM [Log] l INNER JOIN [Level] lv ON l.LevelId = lv.Id /**where**/"; const string selectQuery = @" SELECT * FROM ( SELECT ROW_NUMBER() OVER ( /**orderby**/ ) AS RowNum, l.*, lv.Name as [Level] FROM [Log] l INNER JOIN [Level] lv ON l.LevelId = lv.Id /**where**/ ) AS RowConstrainedResult WHERE RowNum >= (@PageIndex * @PageSize + 1 ) AND RowNum <= (@PageIndex + 1) * @PageSize ORDER BY RowNum"; SqlBuilder builder = new SqlBuilder(); var count = builder.AddTemplate(countQuery); var selector = builder.AddTemplate(selectQuery, new { PageIndex = pageIndex, PageSize = pageSize }); if (!string.IsNullOrEmpty(criteria.Level)) builder.Where("lv.Name= @Level", new { Level = criteria.Level }); if (!string.IsNullOrEmpty(criteria.Message)) { var msg = "%" + criteria.Message + "%"; builder.Where("l.Message Like @Message", new { Message = msg }); } foreach (var a in asc) { if(!string.IsNullOrWhiteSpace(a)) builder.OrderBy(a); } foreach (var d in desc) { if (!string.IsNullOrWhiteSpace(d)) builder.OrderBy(d + " desc"); } var totalCount = connection.Query<int>(count.RawSql, count.Parameters).Single(); var rows = connection.Query<Log>(selector.RawSql, selector.Parameters); return new Tuple<IEnumerable<Log>, int>(rows, totalCount); } }
第二個(gè)示例是通過(guò)Offset/Fetch查詢(支持Sql Server 2012+)
public Tuple<IEnumerable<Log>, int> FindWithOffsetFetch(LogSearchCriteria criteria , int pageIndex , int pageSize , string[] asc , string[] desc) { using (IDbConnection connection = base.OpenConnection()) { const string selectQuery = @" ;WITH _data AS ( SELECT l.*, lv.Name AS [Level] FROM [Log] l INNER JOIN [Level] lv ON l.LevelId = lv.Id /**where**/ ), _count AS ( SELECT COUNT(1) AS TotalCount FROM _data ) SELECT * FROM _data CROSS APPLY _count /**orderby**/ OFFSET @PageIndex * @PageSize ROWS FETCH NEXT @PageSize ROWS ONLY"; SqlBuilder builder = new SqlBuilder(); var selector = builder.AddTemplate(selectQuery, new { PageIndex = pageIndex, PageSize = pageSize }); if (!string.IsNullOrEmpty(criteria.Level)) builder.Where("lv.Name = @Level", new { Level = criteria.Level }); if (!string.IsNullOrEmpty(criteria.Message)) { var msg = "%" + criteria.Message + "%"; builder.Where("l.Message Like @Message", new { Message = msg }); } foreach (var a in asc) { if (!string.IsNullOrWhiteSpace(a)) builder.OrderBy(a); } foreach (var d in desc) { if (!string.IsNullOrWhiteSpace(d)) builder.OrderBy(d + " desc"); } var rows = connection.Query<Log>(selector.RawSql, selector.Parameters).ToList(); if(rows.Count == 0) return new Tuple<IEnumerable<Log>, int>(rows, 0); return new Tuple<IEnumerable<Log>, int>(rows, rows[0].TotalCount); } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
一個(gè)簡(jiǎn)單的ASP.NET Forms 身份認(rèn)證的實(shí)例方法
當(dāng)訪問(wèn)默認(rèn)首頁(yè)default.aspx時(shí),會(huì)自動(dòng)跳轉(zhuǎn)到login.aspx頁(yè)面上請(qǐng)求登錄,隨便輸入用戶名和密碼,點(diǎn)擊“登錄”按鈕,會(huì)回到首頁(yè),并顯示當(dāng)前登錄的用戶名。2013-07-07ASP.NET通過(guò)Remoting service上傳文件
ASP.NET通過(guò)Remoting service上傳文件...2006-09-09.NET醫(yī)院公眾號(hào)系統(tǒng)線程CPU雙高問(wèn)題分析
這篇文章主要介紹了.NET醫(yī)院公眾號(hào)系統(tǒng) 線程CPU雙高分析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04用.NET Core寫(xiě)爬蟲(chóng)爬取電影天堂
本文給大家詳細(xì)介紹了如何使用.NET Core寫(xiě)爬蟲(chóng)爬取電影天堂的方法和詳細(xì)步驟,非常的細(xì)致,有需要的小伙伴可以參考下2016-12-12asp.net利用反射實(shí)現(xiàn)給model類賦值的方法
這篇文章主要介紹了asp.net利用反射實(shí)現(xiàn)給model類賦值的方法,結(jié)合實(shí)例形式分析了asp.net使用反射給model類賦值的操作步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-03-03