Dapper:一款轻量级ORM框架快速学习入门
我们都知道ORM全称叫做Object Relationship Mapper,也就是可以用object来map我们的db,而且市面上的orm框架有很多,其中有一个框架叫做Dapper,而且被称为the king of ORM。Dapper是.NET下一个micro的ORM,它和Entity Framework或Nhibnate不同,属于轻量级的,并且是半自动的。Dapper只有一个代码文件,完全开源,你可以放在项目里的任何位置,来实现数据到对象的ORM操作,体积小速度快。 使用ORM的好处是增、删、改很快,不用自己写sql,因为这都是重复技术含量低的工作,还有就是程序中大量的从数据库中读数据然后创建model,并为model字段赋值。这些ORM都可以轻松给你搞定。ORM给我们开发带来便利时,性能也是一个让我们不得不考虑的问题。一般的ORM性能和直接写原生的sql比都差不少,但是Dapper性能还很错,甚至和DbHelperSQL方式性能高出很多。
Dapper的优势
Dapper是一个轻型的ORM类。代码就一个SqlMapper.cs文件,编译后体积小。
Dapper很快。Dapper的速度接近与IDataReader,取列表的数据超过了DataTable。
Dapper支持多数据库。诸如:Mysql,SqlLite,Mssql系列,Oracle等一系列的数据库。
Dapper的R支持多表并联的对象。支持一对多 多对多的关系。并且没侵入性,想用就用,不想用就不用,无XML无属性,代码以前怎么写现在还怎么写。
Dapper原理通过Emit反射IDataReader的序列队列,来快速的得到和产生对象,性能高。
Dapper支持net2.0及以上版本
Dapper语法十分简单,并且无须迁就数据库的设计。
————————————————
一:为什么选择Dapper
1. 性能优越:
其实在各大网站上,我们大概都会看到这样的一个对比效果图,在超过500次poco serialization的过程中所表现的性能,我们发现dapper是第二名,当然第一名谁也无法超越,越底层的当然久越快,同时也就越麻烦。
2. 支持多数据库
支持多数据库的本质是因为Dapper是对IDBConnection接口进行了方法扩展,比如你看到的SqlMapper.cs,一旦你这样做了,我们也知道,
SqlConnection,MysqlConnection,OracleConnection都是继承于DBConnection,而DBConnection又是实现了IDBConnection的接口,对吧。。。
二:安装Dapper
install dapper的方式通常有两种:
1. 通过nuget进行安装
打开visual studio的项目,依次点击工具
,NuGet包管理器
,管理解决方案的NuGet程序包
;
再点击浏览
,搜索dapper
,点击搜索结果中的Dapper
,勾选项目
,选择安装
;
在解决方案管理器中点击项目
,查看引用
,如果有Dapper
,说明安装成功。
如果你不知道怎么用nuget进行安装,或者不知道install-package是什么,可以在browser上找一下,比如下面这样:
然后我们copy到package console 试试看。
2. 在github上获取源码。
为什么要获取源码,是因为用ilspy调试dapper的源码太费劲了,毕竟现在都是异步编程了,从ilspy中看都是匿名方法很多都无法渗透,废话不多
说,我们只要把Dapper文件夹拉出来然后copy到我们的solution就可以了,如下图:
三:快速CURD操作
其实对数据库的操作莫过于CURD,在进行操作之前我们再配一个Users表。
1. 配置Users表、Product表
--Users表
CREATE TABLE [dbo].[Users]( [UserID] [int] IDENTITY(1,1) NOT NULL, [UserName] [varchar](50) NULL, [Email] [varchar](100) NULL, [Address] [varchar](100) NULL, CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ( [UserID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
--Product表
CREATE TABLE [dbo].[Product](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[ProductName] [varchar](220) NULL,
[ProductDesc] [varchar](220) NULL,
[UserID] [int] NULL,
[CreateTime] [datetime] NULL,
CONSTRAINT [PK_Product] PRIMARY KEY CLUSTERED
(
[ProductID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
2. Insert操作
通常来说,有两种insert操作:
(1)单条insert操作:以下是一个简单的参数化insert,而且还可以塞入匿名类型,对吧,跟原始的SqlParameter相比,是不是简单的多!!!
static void Main(string[] args) { var connectionStr= new SqlConnection("Data Source=.;Initial Catalog=DataMip;Integrated Security=True;MultipleActiveResultSets=True");
using (IDbConnection connection = new SqlConnection(connectionStr)) { connection.Execute("insert into Users values(@UserName,@Email,@Address)", new { UserName = "IvanJiang", Email = "test@163.com", Address = "上海" }); } }
(2) InsertBulk操作
既然是Bulk操作,那肯定就是批量插入了,我们要做的就是将上面这个 ”匿名对象" 变成 ”匿名对象集合“ 就可以了。为了方便操作,这里定义一个Users类,比如下面这样。。。
using (IDbConnection connection = new SqlConnection(connectionStr)) { var list = Enumerable.Range(0, 10).Select(i => new User() { UserName = "test" + i.ToString(), Email = "test" + i.ToString() + "@qq.com", Address = "上海" }); connection.Execute("insert into Users values(@UserName,@Email,@Address)",list);
}
2. Query操作
其实在Dapper在query上提供的的文章太多了。。。这篇我们就按照最简单的参数化查询就好了。。。比如我要找到username=jack的记录,如下:
using (SqlConnection conn = new SqlConnection(connectionStr)) { var res = conn.Query<User>("select * from Users where UserName=@UserName", new { UserName = "test" }).ToList(); res.ForEach(x => Console.WriteLine(String.Format("UserName={0},Email={1}, Address={2}", x.UserName,x.Email,x.Address))); }
其中最大的亮点就在于能够自动化mapper到我们object上面来,这是我们DataReader所不能办到的
3.update操作
这种操作方式,我们还是使用Execute方法来实现,和insert是一种套路的哦。
using (SqlConnection conn = new SqlConnection(connectionStr)) { conn.Execute("update Users set Address='上海' where UserName=@UserName", new { UserName = "test" });
var res1 = conn.Query<User>("select * from Users where UserName=@UserName", new { UserName = "IvanJiang" }).ToList(); res1.ForEach(x => Console.WriteLine(String.Format("UserName={0},Email={1}, Address={2}", x.UserName, x.Email, x.Address))); }
4. delete操作
这里我还是采用参数化的形式来删除UserID=10这条记录,方式如下:
using (SqlConnection conn = new SqlConnection(connectionStr)) { conn.Execute("delete from Users where UserName=@UserName", new { UserName = "IvanJiang" }); }
当然Dapper好玩的地方多着呢,这篇只是一个入门而已,希望本篇对大家有帮助~~~
5.in操作
很多时候我们在manipulate table的时候,或多或少的都会用到 ”in关键字”,比如:我要找到User表中Email in ('5qq.com','8qq.com')
using (SqlConnection conn = new SqlConnection(connectionStr)) {
var sql = "select * from Users where UserID in @UserIDs";
//参数类型是Array的时候,dappper会自动将其转化
var res = conn.Query<User>(sql, new { UserIDs = new int[3] { 4, 5, 6 } }).oList();
res.ForEach(x => Console.WriteLine(String.Format("UserName={0},Email={1}, Address={2}", x.UserName, x.Email, x.Address)));
}
6.多条sql一起执行
有时候我们会想在一条sql中灌入很多的snippet sql,然后让其一起执行,比如:select ... from marketing where id in (....); select .... from eventmarketing where in (...)类似这样的语句。
{
var sqls = "select * from Product; select * from Users";
var multiReader = conn.QueryMultiple(sqls);
var productList = multiReader.Read<Product>().ToList();
var userList = multiReader.Read<User>().ToList();
multiReader.Dispose();
userList.ForEach(x => Console.WriteLine(String.Format("UserName={0},Email={1}, Address={2}", x.UserName, x.Email, x.Address)));
productList.ForEach(x => Console.WriteLine(String.Format("UserName={0},Email={1}, Address={2}", x.UserName, x.Email, x.Address)));
}
7.多表join操作
不管sql写的多么好或者多么烂,接触一个月还是接触到十年,都必然跑不了多表查询,那么在多表查询上dapper该如何使用呢???比如说我要找到2015-12-12之后的商品信息和个人信息,很显然这是一个多表查询,可以先来看一下users和product的关系。
可以发现其实他们有一个外键关系,然后我们在Product Entity上做一下小修改,将Users作为Product的一个entity property。。。
public class Product { public int ProductID { get; set; } public string ProductName { get; set; } public string ProductDesc { get; set; } public Users UserOwner { get; set; } public string CreateTime { get; set; } }
有了这些储备,我们大概就可以写出如下的sql。
using (SqlConnection conn = new SqlConnection(connectionStr))
{ var sql = @"select p.ProductName,p.CreateTime,u.UserName from Product as p join Users as u on p.UserID = u.UserID where p.CreateTime > '2015-12-12'"; var result = conn.Query<Product, Users, Product>(sql, (product, users) => { product.UserOwner = users;
return product; }); }
这是结果就是报错,如下:
从错误信息中可以看到:当你使用multi-mapping的时候要确保设置了splitOn参数,除了Id。。。从这句话中好像也看不出什么名堂,也就是说
除了Id,你都需要设置SplitOn参数,好吧,这是逼着哥哥看源代码。。。。看看SplitOn到底是个什么样的鸟玩法。。。然后我从Call Stack往上
面找,发现了非常”至关重要“的一段话。
然来splitOn就是Dapper对DataReader进行”从右到左“的扫描,这样就可以从sequent中获取到一个subsequent,然后遇到设置的splitOn就停止。原来是这样,就可以将splitOn设置为”UserName“就好了。比如下面这样。。。
using (SqlConnection conn = new SqlConnection(connectionStr))
{ var connection = new SqlConnection("Data Source=.;Initial Catalog=Datamip;Integrated Security=True;MultipleActiveResultSets=True"); var sql = @"select p.ProductName,p.CreateTime,u.UserName from Product as p join Users as u on p.UserID = u.UserID where p.CreateTime > '2015-12-12'; "; var result = connection.Query<Product, Users, Product>(sql, (product, users) => { product.UserOwner = users;
return product; },
splitOn: "UserName"); }
当然如果你觉得我上面说的太啰嗦了,注意事项还tmd的多,又是泛型,又是Lambda的。。。你也可以不指定这些具体Type,而默认使用
dynamic也是可以的,比如下面这样:
8.持存储过程
对于存储过程,也是一个不得不说的话题,Dapper同样也是可以执行存储过程,只需要在Query中的CommandType中标记一下当前就是一个StoredProcedure.
比如现在在Users表上创建一个简单的StoredProcedure。
USE [TEST] GO /****** Object: StoredProcedure [dbo].[sp_GetUsers] Script Date: 09/02/2016 09:14:04 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO Create proc [dbo].[sp_GetUsers] @id int as begin select * from Users where UserID = @id ; end
在这里,我们需要向存储过程塞入一个@id参数,返回具体的Users EntityList,好了,下面再看一下Query如何构造。
{
var res = conn.Query<User>("sp_GetUsers", new { id = 5 }, commandType: CommandType.StoredProcedure).ToList();
res.ForEach(x => Console.WriteLine(String.Format("UserName={0},Email={1}, Address={2}", x.UserName, x.Email, x.Address)));
}
到这里,感觉用Dapper是不是就这么简单,先就说到这里,希望对大家有帮助。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)