基於Dapper的分頁實現,支持篩選,排序,結果集總數,多表查詢,非存儲過程

来源:http://www.cnblogs.com/jinweijie/archive/2017/07/10/dapper_pagination.html
-Advertisement-
Play Games

一個基於Dapper的自定義分頁實現,支持篩選,排序,結果集總數,非存儲過程實現。 ...


簡介

之前事先搜索了下博客園上關於Dapper分頁的實現,有是有,但要麼是基於存儲過程,要麼支持分頁,而不支持排序,或者搜索條件不是那麼容易維護。

代碼

首先先上代碼: https://github.com/jinweijie/Dapper.PagingSample

方法定義

以下是我的一個分頁的實現,雖然不是泛型(因為考慮到where條件以及sql語句的搭配),但是應該可以算是比較通用的了,方法定義如下:

public Tuple<IEnumerable<Log>, int> Find(LogSearchCriteria criteria
            , int pageIndex
            , int pageSize
            , string[] asc
            , string[] desc);

以上函數定義是一個查詢Log的示例,返回結果中,Tuple的第一個值是結果集,第二個值是總行數(例如,總共有100條記錄,每頁10條,當前第一頁,那麼第一個值是10條記錄,第二個值是100)

在示例項目中,我用兩種方法實現了分頁:

1. 第一種是基於2此查詢,第一次得到總數,第二次查詢得到結果集。

2. 第二種是基於1此查詢,用了SqlServer 的Offest/Fetch,所以只支持Sql Server 2012+,所以大家根據自己用的Sql Server版本選擇不同的實現,這裡當然是第二種實現效率更高一點。

運行示例

1. 將Github的Repo下載或者Clone到本地以後,到Database目錄下,解壓縮Database.7z

2. Attach到Sql Server上。預設我使用Sql Server LocalDB,連接字元串是 Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=DapperPagingSample;integrated security=True;   如果你用的不是LocalDB,請酌情修改App.Config的連接字元串。

3. Ctrl+F5運行程式,示例項目里,我用了一個簡單的WinForm程式,但應該可以比較好的演示分頁效果。

多表支持

增加了示例,支持多表查詢,例如有兩個Log表,Level表,Log的LevelId欄位引用Level的Id欄位,通過以下的查詢,可以實現多表查詢的分頁,排序,過濾:

首先是通過兩次查詢的示例(基本支持所有版本Sql Server):

 1 public Tuple<IEnumerable<Log>, int> Find(LogSearchCriteria criteria
 2             , int pageIndex
 3             , int pageSize
 4             , string[] asc
 5             , string[] desc)
 6         {
 7             using (IDbConnection connection = base.OpenConnection())
 8             {
 9                 const string countQuery = @"SELECT COUNT(1)
10                                             FROM      [Log] l
11                                             INNER JOIN [Level] lv ON l.LevelId = lv.Id
12                                             /**where**/";
13 
14                 const string selectQuery = @"  SELECT  *
15                             FROM    ( SELECT    ROW_NUMBER() OVER ( /**orderby**/ ) AS RowNum, l.*, lv.Name as [Level]
16                                       FROM      [Log] l
17                                       INNER JOIN [Level] lv ON l.LevelId = lv.Id
18                                       /**where**/
19                                     ) AS RowConstrainedResult
20                             WHERE   RowNum >= (@PageIndex * @PageSize + 1 )
21                                 AND RowNum <= (@PageIndex + 1) * @PageSize
22                             ORDER BY RowNum";
23 
24                 SqlBuilder builder = new SqlBuilder();
25 
26                 var count = builder.AddTemplate(countQuery);
27                 var selector = builder.AddTemplate(selectQuery, new { PageIndex = pageIndex, PageSize = pageSize });
28 
29                 if (!string.IsNullOrEmpty(criteria.Level))
30                     builder.Where("lv.Name= @Level", new { Level = criteria.Level });
31 
32                 if (!string.IsNullOrEmpty(criteria.Message))
33                 {
34                     var msg = "%" + criteria.Message + "%";
35                     builder.Where("l.Message Like @Message", new { Message = msg });
36                 }
37 
38                 foreach (var a in asc)
39                 {
40                     if(!string.IsNullOrWhiteSpace(a))
41                         builder.OrderBy(a);
42                 }
43 
44                 foreach (var d in desc)
45                 {
46                     if (!string.IsNullOrWhiteSpace(d))
47                         builder.OrderBy(d + " desc");
48                 }
49 
50                 var totalCount = connection.Query<int>(count.RawSql, count.Parameters).Single();
51                 var rows = connection.Query<Log>(selector.RawSql, selector.Parameters);
52 
53                 return new Tuple<IEnumerable<Log>, int>(rows, totalCount);
54             }
55         }

第二個示例是通過Offset/Fetch查詢(支持Sql Server 2012+)

 1 public Tuple<IEnumerable<Log>, int> FindWithOffsetFetch(LogSearchCriteria criteria
 2                                                 , int pageIndex
 3                                                 , int pageSize
 4                                                 , string[] asc
 5                                                 , string[] desc)
 6         {
 7             using (IDbConnection connection = base.OpenConnection())
 8             {
 9                
10                 const string selectQuery = @" ;WITH _data AS (
11                                             SELECT l.*, lv.Name AS [Level]
12                                             FROM      [Log] l
13                                             INNER JOIN [Level] lv ON l.LevelId = lv.Id
14                                             /**where**/
15                                         ),
16                                             _count AS (
17                                                 SELECT COUNT(1) AS TotalCount FROM _data
18                                         )
19                                         SELECT * FROM _data CROSS APPLY _count /**orderby**/ OFFSET @PageIndex * @PageSize ROWS FETCH NEXT @PageSize ROWS ONLY";
20 
21                 SqlBuilder builder = new SqlBuilder();
22                 
23                 var selector = builder.AddTemplate(selectQuery, new { PageIndex = pageIndex, PageSize = pageSize });
24 
25                 if (!string.IsNullOrEmpty(criteria.Level))
26                     builder.Where("lv.Name = @Level", new { Level = criteria.Level });
27 
28                 if (!string.IsNullOrEmpty(criteria.Message))
29                 {
30                     var msg = "%" + criteria.Message + "%";
31                     builder.Where("l.Message Like @Message", new { Message = msg });
32                 }
33                 
34                 foreach (var a in asc)
35                 {
36                     if (!string.IsNullOrWhiteSpace(a))
37                         builder.OrderBy(a);
38                 }
39 
40                 foreach (var d in desc)
41                 {
42                     if (!string.IsNullOrWhiteSpace(d))
43                         builder.OrderBy(d + " desc");
44                 }
45                 
46                 var rows = connection.Query<Log>(selector.RawSql, selector.Parameters).ToList();
47 
48                 if(rows.Count == 0)
49                     return new Tuple<IEnumerable<Log>, int>(rows, 0);
50                 
51 
52                 return new Tuple<IEnumerable<Log>, int>(rows, rows[0].TotalCount);
53                 
54             }
55         }

 

謝謝

希望對大家有幫助:)

最後,我更新了本篇隨便,增加了內容,希望不要再被撤下了(上次撤下說是因為篇幅太短。。。),因為個人覺得這個對大家應該還是會有用的。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 廢話不多說,直接上步驟。 1、文件準備 下載皮膚文件,將解壓後的Skinssk文件夾放在程式根目錄(bin\\debug)下。 皮膚文件下載地址:http://pan.baidu.com/s/1slSAqFN 2、添加工程引用 右鍵引用->點擊添加引用->瀏覽->選擇剛剛放在debug目錄下Skin ...
  • Create a web API with ASP.NET Core MVC and Visual Studio for Windows 在windows上用vs與asp.net core mvc 創建一個 web api 程式 2017-5-24 8 分鐘閱讀時長 本文內容 1.Overview ...
  • 首先對 Center 進行一個簡單的佈局 然後就是在js裡面完成tabs的點擊事件實現了 其實center就是在div裡面嵌入了一個iframe,所以最後返回的就是一個iframe 這裡需要註意一點就是上面的detail是導航欄的類選擇器的值(這裡的class一定要一樣) 整個頁面代碼 ...
  • ef中,我們創建外鍵的時候需要註意,否則會出現標題所示問題。 例:有項目表,項目收藏表,用戶表 項目表有如下欄位:ProjectId,InputPersonId等 項目收藏表有如下欄位:ProjectId,UseId等 用戶表有如下欄位:用戶id等 項目表: 項目收藏表: 用戶表: 分析一下,假如刪 ...
  • 我們先來簡單瞭解一下WinForm和FarPoint,WinForm是·Net開發平臺中對Windows Form的一種稱謂。而FarPoint是一款模擬EXCEL的控制項。它可以根據用戶的要求實現很大部份的EXCEL操作,且包括多個子表、表格風格定義、公式計算、排序、分組等等都可以實現。本文主要是介 ...
  • 配置的同步涉及到兩個方面:第一,對原始的配置文件實施監控併在其發生變化之後從新載入配置;第二,配置重新載入之後及時通知應用程式進而使後者能夠使用最新的配置。接下來我們利用一個簡單的.NET Core控制台應用來演示針對文件的配置會涉及到數據同步的問題,我們希望應用能夠對原始配置文件實施監控,併在文件 ...
  • ASP是動態伺服器頁面(ActiveServerPage)的英文縮寫,是微軟公司開發的代替CGI腳本程式的一種應用,它可以與資料庫和其它程式進行交互,是一種簡單、方便的編程工具。那麼關於ASP.NET頁面事件的知識點,你又瞭解多少呢? 大家可以看到其實在ASP.NET(ASP.NET是.NETFra ...
  • Internet上有著極其龐大的資源信息,各行各業的信息無所不有。網頁的信息搜集就是獲取網頁的數據,然後通過程式分析,將有用的數據提取分離出來。搜索引擎工作的一部分就是網頁數據抽取。比如編製程式抽取新浪網新聞頻道里的這個新聞的標題就是一種網頁數據抽取。 獲取網頁數據有很多種方式。網頁信息收集器可以很 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...