基于Dapper实现分页效果 支持筛选、排序、结果集总数等

 更新时间:2017年07月26日 15:14:58   作者:JIN Weijie  
这篇文章主要为大家详细介绍了基于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):

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);
      }
    }

第二个示例是通过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);
        
      }
    }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Asp.net MVC 对所有用户输入的字符串字段做Trim处理的方法

    Asp.net MVC 对所有用户输入的字符串字段做Trim处理的方法

    这篇文章主要介绍了Asp.net MVC 如何对所有用户输入的字符串字段做Trim处理,需要的朋友可以参考下
    2017-06-06
  • Hangfire在ASP.NET CORE中的简单实现方法

    Hangfire在ASP.NET CORE中的简单实现方法

    下面小编就为大家分享一篇Hangfire在ASP.NET CORE中的简单实现方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-11-11
  • ASP.NET OutputCache详解

    ASP.NET OutputCache详解

    这篇文章主要介绍了ASP.NET OutputCache详解,本文详细讲解了OutputCache的语法、OutputCache的参数、OutputCache使用示例等内容,需要的朋友可以参考下
    2015-06-06
  • 浅谈ASP.Net Core WebApi几种版本控制对比

    浅谈ASP.Net Core WebApi几种版本控制对比

    这篇文章主要介绍了浅谈ASP.Net Core WebApi几种版本控制对比,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • asp.net SQL存储过程分页

    asp.net SQL存储过程分页

    上周花一下午时间写了个分页.给大家分享下,如果写得不好请大家指出一起讨论哈,小弟第一次写文章哈..谢谢.
    2009-05-05
  • 高效的.Net UDP异步编程实现分析

    高效的.Net UDP异步编程实现分析

    重点是怎么建立一种高效的UDP机制来实时接收服务器发送过来的数据包.本文将介绍.Net UDP异步编程如何实现解决方案,有需求的朋友可以参考下
    2012-11-11
  • asp.net get set用法

    asp.net get set用法

    属性的定义和使用 属性由两个部分组成:属性头和存储器。存储器分为get访问器和set访问器。声明属性的一般形式为: 修饰符 类型 属性名
    2008-05-05
  • asp.net(C#) 生成随机验证码的代码

    asp.net(C#) 生成随机验证码的代码

    asp.net(C#) 生成随机验证码的代码...
    2007-04-04
  • .Net RabbitMQ实现HTTP API接口调用

    .Net RabbitMQ实现HTTP API接口调用

    RabbitMQ Management插件还提供了基于RESTful风格的HTTP API接口来方便调用。本文就主要介绍了.Net RabbitMQ实现HTTP API接口调用,感兴趣的可以了解一下
    2021-06-06
  • C#反射技术的简单操作(读取和设置类的属性)

    C#反射技术的简单操作(读取和设置类的属性)

    反射的作用想必大家都知道了吧,少量属性的自动化操作手动添加几下当然是没有问题的,但是属性数量较多的时候敲起这些繁锁的代码可以困了,再说对扩展和维护性造成很多的不遍,以下代码中如不能直接使用请添加using System.Text;的引用。
    2011-01-01

最新评论