本文内容

  • 特点
  • 性能
  • 参数化的查询
  • List 支持
  • 缓存和非缓存的 readers
  • 多个映射
  • 多个结果
  • 存储过程
  • Ansi Strings 和 varchar
  • 限制和注意事项
  • Dapper 能运行在我的 db 提供者上吗?
  • 有例子的完整例子列表吗?
  • 谁在使用 Dapper?
  • 参考

跳槽了,新公司的数据库层,准确地说,数据库层和持久层使用 Dapper,这东西的确很方便~个人觉得这种方便性体现在三点:

  1. 能很方便地执行数据库 DML 和 DLL 操作。比如,当你执行一个带参数的 SQL 时,SQL 中的变量能与你传递给它的实体或匿名对象中的属性,自定匹配。而我们知道,带参数的 SQL,能提高数据库执行 SQL 的效率;
  2. 能很方便地将数据库检索结果映射为面向对象的对象。从数据库中的检索结果,通常是张二维表,如 DataTable,而应用程序中是实体类,以及实体类的集合,那么 Dapper 能够将 DataTable 自动地映射成为实体类的集合;
  3. 能很方便地书写 SQL 语句。比如,写多个 SQL,用分号分隔。

下载 Demo

(该下载包含 Dapper 项目,项目中有 Dapper 的测试示例和性能测试例子)

(Dapper 的示例使用 SQLServer 数据库,我个人的示例是 MySQL)

特点


Dapper 只有一个文件,你可以把它拖到你的项目中,来扩展你的 IDbConnection 接口。

它提供了三方面的帮助:

执行一个查询,并把结果映射到一个强类型 list

注意:所有的扩展方法都假设数据库连接已打开,如果关闭连接,它们将失败。

public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param = null, SqlTransaction transaction = null, bool buffered = true)

用法:

public class Dog

{

    public int? Age { get; set; }

    public Guid Id { get; set; }

    public string Name { get; set; }

    public float? Weight { get; set; }

 

    public int IgnoredProperty { get { return 1; } }

}            

 

var guid = Guid.NewGuid();

var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid });

 

dog.Count()

    .IsEqualTo(1);

 

dog.First().Age

    .IsNull();

 

dog.First().Id

    .IsEqualTo(guid);

执行一个查询,并把结果映射到一个动态 object 的 list

public static IEnumerable<dynamic> Query (this IDbConnection cnn, string sql, object param = null, SqlTransaction transaction = null, bool buffered = true)

该方法将执行 SQL,并返回一个动态 list,即 var 变量。

用法:

var rows = connection.Query("select 1 A, 2 B union all select 3, 4");

 

((int)rows[0].A)

   .IsEqualTo(1);

 

((int)rows[0].B)

   .IsEqualTo(2);

 

((int)rows[1].A)

   .IsEqualTo(3);

 

((int)rows[1].B)

    .IsEqualTo(4);

rows[0] 这种访问方式会出错,不知道示例是怎么给的~

执行一个不返回结果的 Command

public static int Execute(this IDbConnection cnn, string sql, object param = null, SqlTransaction transaction = null)

用法:

connection.Execute(@"

  set nocount on 

  create table #t(i int) 

  set nocount off 

  insert #t 

  select @a a union all select @b 

  set nocount on 

  drop table #t", new {a=1, b=2 })

   .IsEqualTo(2);

多次执行一个 Command


相同的签名也可以让你方便高效地对一个命令执行多次,例如批量加载数据(bulk-load data)。

用法:

connection.Execute(@"insert MyTable(colA, colB) values (@a, @b)",

    new[] { new { a=1, b=1 }, new { a=2, b=2 }, new { a=3, b=3 } }

  ).IsEqualTo(3); // 3 rows inserted: "1,1", "2,2" and "3,3"

对任何类型实现 TIEnumerable 的参数都可以执行。

性能


Dapper 的主要特点是性能。以下数据显示对一个数据库执行 SELECT 出 500 条,并把数据映射到对象中需要多长时间。

性能测试分为三个方面:

  • POCO 序列化框架,支持从数据库获得静态类型的对象。使用原始的 SQL。
  • 动态序列化框架,支持返回对象的动态列表。
  • 典型的框架用法。往往不会涉及编写 SQL。

Performance of SELECT mapping over 500 iterations - POCO 序列化

方法

持续时间(毫秒)

备注

Hand coded (using a SqlDataReader)

47

Can be faster

Dapper ExecuteMapperQuery

49

同上

ServiceStack.OrmLite (QueryById)

50

同上

PetaPoco 

52

同上

BLToolkit

80

同上

SubSonic CodingHorror

107

同上

NHibernate SQL

104

同上

Linq 2 SQL ExecuteQuery

181

同上

Entity framework ExecuteStoreQuery

631

同上

Performance of SELECT mapping over 500 iterations - dynamic 序列化

方法

持续时间(毫秒)

备注

Dapper ExecuteMapperQuery (dynamic)

48

 

Massive

52

 

Simple.Data

95

 

Performance of SELECT mapping over 500 iterations - 典型用法

方法

持续时间(毫秒)

备注

Linq 2 SQL CompiledQuery

81

Not super typical involves complex code

NHibernate HQL

118

 

Linq 2 SQL

559

 

Entity framework

859

 

SubSonic ActiveRecord.SingleOrDefault

3619

 

参数化的查询


参数可以作为匿名类来传递。这使你可以轻松地给命名参数,只要简单地剪切和粘贴 SQL 片断,并在查询分析器中执行即可。

new {A = 1, B = "b"} // A will be mapped to the param @A, B to the param @B 

List 支持


Dapper 运行让你传递 IEnumerable,自动地参数化的查询。

例如下面 SQL 的 in 查询:

connection.Query<int>("select * from (select 1 as Id union all select 2 union all select 3) as X where Id in @Ids", new { Ids = new int[] { 1, 2, 3 });

将被翻译为:

select * from (select 1 as Id union all select 2 union all select 3) as X where Id in (@Ids1, @Ids2, @Ids3)" // @Ids1 = 1 , @Ids2 = 2 , @Ids2 = 3

缓存和非缓存的 readers


Dapper 的默认动作是执行 SQL 并在返回时缓冲整个 reader。在大多数情况下,这是理想的,因为它能最大限度地减少数据库中的共享锁,以及减少数据库的网络时间。

但是,在执行庞大查询时,你可能为了减少内存的占用,只加载需要的对象。要做到这点,通过缓冲到查询方法中。

/// <summary>

/// NonBuffered

/// 将会抛出异常,Invalid attempt to Read when reader is closed.

/// </summary>

public static void TestBasicStringUsageAsyncNonBuffered()

{

    var query = DbHelp.QueryAsync<string>(new CommandDefinition("select 'abc' as Value union all select @txt", new { txt = "def" }, flags: CommandFlags.None));

    var arr = query.Result.ToArray();

    arr.IsSequenceEqualTo(new[] { "abc", "def" });

}

 

/// <summary>

/// Buffered

/// 不会抛出异常

/// </summary>

public static void TestBasicStringUsageAsyncBuffered()

{

    var query = DbHelp.QueryAsync<string>(new CommandDefinition("select 'abc' as Value union all select @txt", new { txt = "def" }, flags: CommandFlags.Buffered));

    var arr = query.Result.ToArray();

    arr.IsSequenceEqualTo(new[] { "abc", "def" });

}

/// <summary>

/// Pipelined

/// 将会抛出异常,Invalid attempt to Read when reader is closed.

/// </summary>

public static void TestBasicStringUsageAsyncPipelined()

{

    var query = DbHelp.QueryAsync<string>(new CommandDefinition("select 'abc' as Value union all select @txt", new { txt = "def" }, flags: CommandFlags.Pipelined));

    var arr = query.Result.ToArray();

    arr.IsSequenceEqualTo(new[] { "abc", "def" });

}

多个映射


Dapper 允许你把单行映射到多个对象。如果你想避免额外的查询和加载关联,那么这个功能就很关键了。

例如:

var sql = 

@"select * from #Posts p 

left join #Users u on u.Id = p.OwnerId 

Order by p.Id";

 

var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post;});

var post = data.First();

 

post.Content.IsEqualTo("Sams Post1");

post.Id.IsEqualTo(1);

post.Owner.Name.IsEqualTo("Sam");

post.Owner.Id.IsEqualTo(99);

提示:Dapper 假定你的 ID 列被命名为“ID”或“id”,如果你的主键是不同的,或者你想在点上拆分宽行点,而不是“ID”,可以使用可选的'splitOn'参数。

多个结果


Dapper 允许你在一次查询中处理多个结果的集合。

例如:

var sql = 

@"

select * from Customers where CustomerId = @id

select * from Orders where CustomerId = @id

select * from Returns where CustomerId = @id";

 

using (var multi = connection.QueryMultiple(sql, new {id=selectedId}))

{

   var customer = multi.Read<Customer>().Single();

   var orders = multi.Read<Order>().ToList();

   var returns = multi.Read<Return>().ToList();

   ...

} 

存储过程


Dapper 完全支持存储过程:

var user = cnn.Query<User>("spGetUser", new {Id = 1}, 

        commandType: CommandType.StoredProcedure).First();}}}

如果你想要更灵活的操作,可以这样做:

var p = new DynamicParameters();

p.Add("@a", 11);

p.Add("@b", dbType: DbType.Int32, direction: ParameterDirection.Output);

p.Add("@c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);

 

cnn.Execute("spMagicProc", p, commandType: CommandType.StoredProcedure); 

 

int b = p.Get<int>("@b");

int c = p.Get<int>("@c"); 

Ansi Strings 和 varchar


Dapper 支持 varchar 参数,如果你在一个 varchar 列上执行一个 where 语句,确保下面方式传递参数:

Query<Thing>("select * from Thing where Name = @Name", new {Name = new DbString { Value = "abcde", IsFixedLength = true, Length = 10, IsAnsi = true });

在 SQL Server 上,当查询非 Unicode 时,查询 Unicode 和 ANSI 时需要使用 Unicode。

限制和注意事项


对于 Dapper 执行的每个查询的缓存信息,使得它能够快速地物化对象和处理参数。当前的实现把信息缓存在一个 ConcurrentDictionary 对象中。它存储的对象永远不会被刷新。如果你生成的 SQL 字符串没有使用参数,那么可能会出现命中内存问题。我们把字典转换成 LRU(Least Recently Used)缓存。

ORM 的很多特点都被 Dapper 去掉了,没有身份地图(Identity Map),没有更新/选择的助手等。

Dapper 不会管理你连接的生命周期,它假定它得到的连接是打开的,并且不存在 DataReader 枚举(除非启用 MARS)。

什么是 Mars?它是在创建数据库连接时指定的,下面是 Dapper 中连接 SQL Server 的示例:

public static SqlConnection GetOpenConnection(bool mars = false)

{

    var cs = connectionString;

    if (mars)

    {

        SqlConnectionStringBuilder scsb = new SqlConnectionStringBuilder(cs);

        scsb.MultipleActiveResultSets = true;

        cs = scsb.ConnectionString;

    }

    var connection = new SqlConnection(cs);

    connection.Open();

    return connection;

}

如果指定了 Mars,那么还会创建 SqlConnectionStringBuilder,并指定其 MultipleActiveResultSets 属性为 true。不过,看 Dapper 的例子,貌似 SQL Server 是有 Mars 的,但 MySQL 没有。

Dapper 能运行在我的 db 提供者上吗?


Dapper 能运行在所有 .net ado 提供者上,包括 sqlite,sqlce,firebird,oracle,MySQL,PostgreSQL 和 SQL Server。

有例子的完整例子列表吗?


Dapper 在测试项目中有完整的测试套件。

谁在使用 Dapper?


目前使用 Dapper 的有 Stack Overflowhelpdesk

(if you would like to be listed here let me know)

参考资料


 

下载 Demo

Dapper - .Net 环境下一个简单对象映射的框架的更多相关文章

  1. Net环境下比较流行的ORM框架对比

    个人感觉在Java领域大型开发都离不了ORM的身影,所谓的SSH就是Spring+Struts+Hibernate,除了在学习基础知识的时候被告知可以使用JDBC操作数据库之外,大量的书籍中都是讲述使 ...

  2. C语言 在VS环境下一个很有意思的报错:stack around the variable was corrupted

    今天做一个很简单的oj来温习下c 语言 题目如下 输入 3位正整数 输出 逆置后的正整数 代码如下: #include"stdio.h"int main(){ float h,su ...

  3. 基于python3环境下搭建Robot Framework 自动化测试框架(一)

    大家都知道,Robot Framework 是基于python2 环境 的一套自动化测试工具,据说python 2 到2020年不维护,现在用python 3 的环境搭建Robot Framework ...

  4. java 在linux环境下写入 syslog 问题研究

    1.Syslog 在Unix类操作系统上,syslog广泛应用于系统日志.syslog日志消息既可以记录在本地文件中,也可以通过网络发送到接收syslog的服务器.接收syslog的服务器可以对多个设 ...

  5. C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 VC中进程与进程之间共享内存 .net环境下跨进程、高频率读写数据 使用C#开发Android应用之WebApp 分布式事务之消息补偿解决方案

    C# .Net 多进程同步 通信 共享内存 内存映射文件 Memory Mapped 转 节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing). ...

  6. Java CAS同步机制 原理详解(为什么并发环境下的COUNT自增操作不安全): Atomic原子类底层用的不是传统意义的锁机制,而是无锁化的CAS机制,通过CAS机制保证多线程修改一个数值的安全性。

    精彩理解:  https://www.jianshu.com/p/21be831e851e ;  https://blog.csdn.net/heyutao007/article/details/19 ...

  7. 实践.Net Core在Linux环境下的第一个Hello World

    基础环境和相关软件准备 1.CentOS7.1 64位系统(或者其他CentOS版本的64位系统) 2.WinSCP软件(主要是方便管理和编辑Linux系统的文件) 3.XShell软件(Window ...

  8. Linux环境下部署完JDK后运行一个简单的Java程序

    前言 前一篇文章详细讲解了如何在Windows环境下安装虚拟机+Linux系统,并且成功部署了JDK. 不过部署完JDK之后,我们判断部署是否成功的依据是看"java -version&qu ...

  9. 在android源码环境下写上层应用的一个初步解决方法

    在android源码环境下编写上层应用,一直以来我都觉得很麻烦.因为如果单纯将应用导入eclipse,那么framework层一些定制的API无法自动提示和补全,使用起来不太方便:如果将整个andro ...

随机推荐

  1. gnu--libc

    https://www.gnu.org/software/libc/manual/html_node/index.html

  2. Redis源代码分析(三十五)--- redis.c服务端的实现分析(2)

    在Redis服务端的代码量真的是比較大,假设一个一个API的学习怎么实现,无疑是一种效率非常低的做法,所以我今天对服务端的实现代码的学习,重在他的运行流程上.而对于他的模块设计在上一篇中我已经分析过了 ...

  3. Windows XP Manifest in Delphi

    Find out how you can include the manifest into a Delphi project to allow your application to share t ...

  4. Java io.netty.util.ReferenceCountUtil 代码实例

    原文:https://www.helplib.com/Java_API_Classes/article_64580 以下是展示如何使用io.netty.util.ReferenceCountUtil的 ...

  5. C#编程(五十八)----------并行集合

    并行集合 对于并行任务,与其相关紧密的就是对一些共享资源,数据结构的并行访问.经常要做的就是对一些队列进行加锁-解锁,然后执行类似插入,删除等等互斥操作. .NET4提供了一些封装好的支持并行操作数据 ...

  6. C#编程(三十二)----------数组基础

    数组 如果需要使用同一类型的多个对象,就可以使用数组.数组是一种数据结构,他可以包含同一类型的多个元素. 数组的声明 在声明数组时,应先定义数组中元素的类型,其后是一对方括号核一遍变量名.例如:生命一 ...

  7. 现场故障-数据量超出plsql developer结果集导致应用程序无数据现象

    情景重现: 维护人员想要用plsql developer工具查看一年前某表的数据,表中数据约30W行,因为此时无业务,维护人员关闭了应用程序.查询时选择了将所有数据所有列出,结果在显示到3W多行时,弹 ...

  8. java List集合记录 ArrayList和LinkedList的区别

    一般大家都知道ArrayList和LinkedList的大致区别:      1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构.      2.对于随机访问 ...

  9. 玩转Eclipse — 自动代码生成的Java Code Template

    文章转载地址:点击打开链接 当代码写到一定程度之后,就会发现很多代码都被重复地敲了N多遍,甚至毫不夸张地说:闭着眼睛都能敲出来.大量地敲这些重复地代码,除了锻炼敲键盘的速度,基本上没有其他益处,但是长 ...

  10. IT狂人第一至四季/全集The IT Crowd迅雷下载

    本季第一至四季 The IT Crowd (2006)看点:<IT狂人>史上最囧,最雷,最脑残,最出乎意料,最不按常理出牌的IT “精英们”登上银屏了.让超擅长收发邮件.单击和双击鼠标的I ...