C# 数据操作系列 - 17 Dapper ——号称可以与ADO.NET 同台飙车的ORM_c# dapper update-程序员宅基地

技术标签: c#  C#教程  

  1. 前言
    之前四篇介绍了一个国内开发者开发的优秀框架SqlSugar,给我们眼前一亮的感觉。这一篇,我们将试试另一个出镜率比较高的ORM框架-Dapper。

Dapper是一个轻量级的ORM框架,其以高速、简单易用为特点。在某些时候,效率甚至可以与ADO.NET 媲美。那么,吹得天花乱坠,就让我们实际看看它的表现吧。

  1. 开始使用
    照例,先创建一个项目:DapperDemo

dotnet new console --name DapperDemo
然后切换到目录里:

cd DapperDemo
添加包支持:

dotnet add package Dapper
如果不出意外的话,目前项目中已经安装好了Dapper。现在就让我们开始愉快的使用吧。

首先,需要注意的一点是,与其他的ORM框架不同的是,Dapper需要我们手动创建一个IConnection。Dapper的所有操作都是依托于IConnection来操作,而且Dapper将其支持的方法封装成了IConnection的扩展方法。

所以,在使用之前我们需要先创建一个IConnection。为了方便演示,我把之前SqlSugar演示用过的测试数据库拿过来了,是一个SQLite,所以我们需要先安装一个SQLite的驱动:

dotnet add package Microsoft.Data.SQLite
在Program.cs中引入两个包:

using Microsoft.Data.Sqlite;
using Dapper;

在Main方法里创建一个IConnection:

using(var connection = new SqliteConnection("Data Source=./demo.db"))
{
    
    
}
  1. 多数据查询
    Dapper的查询相当简单:

var result = connection.Query(“select * from Persion”);
传入一个SQL语句,返回一个可枚举对象。如果不指定类型,将返回类型为dynamic的列表。我们来看一下Query方法的相关声明:

public static IEnumerable<dynamic> Query(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null);

public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null);

public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string sql, Type[] types, Func<object[], TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null);

我们就以最常用的三个为例,给大伙分析一下参数以及调用方式:

cnn 一个数据库连接,所以Dapper不负责管理数据库连接,这部分由我们手动管理
sql 传入的SQL语句,Dapper以IDbConnection为基础,以SQL为执行命令,所以必须我们来传入SQL语句
param 一个可以为Null的Object类型,表示SQL的参数化,Dapper对参数化做了一些优化,在SQL的参数化里,参数名映射到了object的属性上。
transaction 表示是否有IConnection级别的事务,默认为null,传入后该指令会被事务包含
buffered 缓存
commandTimeout 命令执行是否超时以及超时时间
commandType 表示命令模式 有 Text 普通模式,StoredProcedure 存储过程 ,TableDirect 表查询
splitOn 默认情况下以Id 作为两个对象之间的区分
3. 单数据查询
Dapper在数据查询方面不仅支持集合作为查询结果,还可以获取单个数据。

一共有四种方式获取单数据:

public static T QueryFirst(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);
public static T QueryFirstOrDefault(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);
QueryFirst 表示获取第一条查询结果,如果没有结果,则会抛出一个异常。

QueryFirstOrDefault 与QueryFirst一样,但不同的是,如果没有则不会抛出异常,而是直接返回一个该类型的默认值,数值类型的默认值为(0),引用类型的默认值为Null。

public static T QuerySingle(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);
public static T QuerySingleOrDefault(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);
QuerySingle也能查询单条数据作为结果,但与QueryFirst不同的是QuerySingle查询时,如果数据存在多行将会抛出异常,如果不想要异常则可以使用QuerySingleOrDefault作为查询方法。

  1. QueryMultiple
    这个另外一种查询方式,对于SQL语句来说,没有明显的限制,所以我们有时候可以传入多个查询SQL语句进去,然后分别获取来自各个表的查询数据:
string sql = "SELECT * FROM Invoice WHERE InvoiceID = @InvoiceID; SELECT * FROM InvoiceItem WHERE InvoiceID = @InvoiceID;";

using (var connection = My.ConnectionFactory())
{
    
    connection.Open();

    using (var multi = connection.QueryMultiple(sql, new {
    InvoiceID = 1}))
    {
    
        var invoice = multi.Read<Invoice>().First();
        var invoiceItems = multi.Read<InvoiceItem>().ToList();
    }
}

看一下它的基本参数和方法声明:

public static GridReader QueryMultiple(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);

这个方法返回一个GridReader,通过Read方法获取需要的数据。

  1. 不只是查询
    Dapper当然不只有查询这一项功能,Dapper支持使用存储过程、insert、update、delete等其他的SQL语句进行操作数据库。使用方式:
string sql = "Invoice_Insert";

using (var connection = My.ConnectionFactory())
{
    
    var affectedRows = connection.Execute(sql,
        new {
    Kind = InvoiceKind.WebInvoice, Code = "Single_Insert_1"},
        commandType: CommandType.StoredProcedure);
    var affectedRows2 = connection.Execute(sql,
        new[]
        {
    
            new {
    Kind = InvoiceKind.WebInvoice, Code = "Many_Insert_1"},
            new {
    Kind = InvoiceKind.WebInvoice, Code = "Many_Insert_2"},
            new {
    Kind = InvoiceKind.StoreInvoice, Code = "Many_Insert_3"}
        },
        commandType: CommandType.StoredProcedure
    );
}


示例就是使用存储过程的例子。


string sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);";

using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
    
    var affectedRows = connection.Execute(sql, new {
    CustomerName = "Mark"});

    Console.WriteLine(affectedRows);

    var customer = connection.Query<Customer>("Select * FROM CUSTOMERS WHERE CustomerName = 'Mark'").ToList();

    FiddleHelper.WriteTable(customer);
}
//== 多次插入
string sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);";

using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
    
    connection.Open();

    var affectedRows = connection.Execute(sql,
    new[]
    {
    
    new {
    CustomerName = "John"},
    new {
    CustomerName = "Andy"},
    new {
    CustomerName = "Allan"}
    }
);

这是执行插入的示例。

string sql = "UPDATE Categories SET Description = @Description WHERE CategoryID = @CategoryID;";

using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
                
    var affectedRows = connection.Execute(sql,new {
    CategoryID = 1, Description = "Soft drinks, coffees, teas, beers, mixed drinks, and ales"});

    Console.WriteLine(affectedRows);
}

更新。

string sql = "DELETE FROM Customers WHERE CustomerID = @CustomerID";

using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
                
    var affectedRows = connection.Execute(sql, new {
    CustomerID = 1});

    Console.WriteLine(affectedRows);
}

删除。

Execute没什么好说的,基本就是执行SQL语句的形式完成增删改成等操作。

值得注意的是:

public static IDataReader ExecuteReader(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);

返回一个IDataReader实例,这个实例可以给DataTable填充vb.net教程数据,使用方法如下:

DataTable table = new DataTable();
table.Load(reader);
以及:

public static T ExecuteScalar<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);

这个方法是返回查询结果的第一行第一列的元素。

  1. 总结
    如果单说Dapper的话,并没有太多好说的。不过Dapper是真的快,在实际开发中有时候会用Dapper作为EF Core的一个补充。

当然了,Dapper还有很多其他的插件,使用那些插件c#教程可以为Dappe带来非一般的提升。我们下一篇将介绍一下Dapper的插件。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/chinaherolts2008/article/details/111950978

智能推荐

[译]使用MVI打造响应式APP(四):独立性UI组件-程序员宅基地

文章浏览阅读130次。原文:REACTIVE APPS WITH MODEL-VIEW-INTENT - PART4 - INDEPENDENT UI COMPONENTS作者:Hannes Dorfmann译者:却把清梅嗅这篇博客中,我们将针对如何 如何构建独立组件 进行探讨,我将阐述为什么在我看来 父子关系会导致坏味道的代码,以及为何这种关系是没有意义的。有这样一个问题时不时涌现在我的脑海中—— MVI...

tensorflow经过卷积及池化层后特征图的大小计算_池化层后特征图尺寸-程序员宅基地

文章浏览阅读662次。https://blog.csdn.net/qq_32466233/article/details/81075288_池化层后特征图尺寸

使用vue-echarts异步数据加载,不能重新渲染页面问题。_vue echart初始化渲染过后无法重新渲染-程序员宅基地

文章浏览阅读3.3k次。一、问题说明我是用的是官方示例中的这个饼状图。结果在应用到项目中后发现利用axios请求到的数据无法渲染到页面中去。并且其中value值已经改变。二、解决办法用$set改变value的值,并且重新绘制一遍表格。$set是全局 Vue.set 的别名。$set用法:向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新属性,因为..._vue echart初始化渲染过后无法重新渲染

nrf51822 蓝牙协议栈 例程入门 点灯_nrf51822例程-程序员宅基地

文章浏览阅读6.6k次。1,参考文档: 青云蓝牙光盘V4.1\6.青云系列教程青风出品\3:BLE蓝牙应用篇\2.BLE实验第二节:蓝牙LED任务读写使用说明.pdf青云蓝牙光盘V4.1\6.青云系列教程青风出品\4:蓝牙原理详解手把手教你用蓝牙:蓝牙LED任务读写原理任务详解.pdf2,进入目录: 青云蓝牙光盘V4.1\5.青云测试代码\ 第三部分:BLE蓝牙实验\BLE实验3:按键蓝牙通知\B..._nrf51822例程

TortoiseGit小乌龟工具上传解析-程序员宅基地

文章浏览阅读5.2k次。使用tortoiseGit工具一直出错,由于没有设置自动获取putty key这一项,从网上找了一个教程,现分享如下,以做参考:前半部分参考网上的例子:http://www.showerlee.com/archives/1300,但会出现“git did not exit cleanly (exit code 128)”错误1.在D盘新建一个目录,例如"D:\Git",并进入目录右键目录空白处选择...

bindgetuserinfo="onGotUserInfo" and @getuserinfo="onGotUserInfo_component "pages/index/index" does not have a meth-程序员宅基地

文章浏览阅读1.9k次。发现使用uni-app获取UserInfo,结果使用微信官网栗子发现只弹出提示,没获取到值如下<button open-type="getUserInfo" lang="zh_CN" bindgetuserinfo="onGotUserInfo">获取用户信息</button>onGotUserInfo: function (e) { console.log(e) ..._component "pages/index/index" does not have a method "getuserinfo" to handle

随便推点

python translate函数_Python:内置函数makestrans()、translate()-程序员宅基地

文章浏览阅读287次。一、makestrans()格式: str.maketrans(intab,outtab);功能:用于创建字符映射的转换表,对于接受两个参数的最简单的调用方式,第一个参数是字符串,表示需要转换的字符,第二个参数也是字符串表示转换的目标。注:两个字符串的长度必须相同,为一一对应的关系。注:Python3.6中已经没有string.maketrans()了,取而代之的是内建函数:bytearray...._python maketrance

Set集合详解-程序员宅基地

文章浏览阅读5.7k次,点赞9次,收藏14次。set集合的简介,它的特点和遍历方式。介绍了HashSet重复元素存储底层原理,LinkedHashSet,TreeSet排序方法,SortedSet获取集合值的方法_set集合

详解智慧城市排水管理系统整体方案_污水处理智慧管理系统案列-程序员宅基地

文章浏览阅读3.6k次,点赞3次,收藏29次。随着城市规模的不断扩大和现代化程度的日益提高,城市排水管网越来越复杂,一些城市相继发生大雨内涝、管线泄漏爆炸、路面塌陷等事件,严重影响了人民群众生命财产安全和城市运行秩序。因此,摸清排水管网设施资产家底、建立排水管网地理信息系统,用现代化的技术手段对排水系统进行科学管理显得迫在眉睫。以时空信息为基础,充分利用感知监测网、物联网、云计算、移动互联网、工业控制和水力模型等新一代信息技术,全方位感..._污水处理智慧管理系统案列

详解NTFS文件系统_ntfs文件系统中,磁盘上的所有数据包括源文件都是以什么的形式存储-程序员宅基地

文章浏览阅读5.7k次,点赞4次,收藏13次。上篇在详解FAT32文件系统中介绍了FAT32文件系统存储数据的原理,这篇就来介绍下NTFS文件系统。NTFS、用过Windows系统的人都知道,它是一个很强大的文件系统,支持的功能很多,存储的原理也很复杂。目前绝大多数Windows用户都是使用NTFS文件系统,它主要以安全性和稳定性而闻名,下面是它的一些主要特点。安全性高:NTFS支持基于文件或目录的ACL,并且支持加密文件系统(E_ntfs文件系统中,磁盘上的所有数据包括源文件都是以什么的形式存储

【深度学习】【目标检测】损失函数smooth L1 Loss_smooth_l1_loss公式-程序员宅基地

文章浏览阅读1.2k次。pytorch之常用Loss函数总结参考文档L1、L2、smooth L1 Losssoftmax_cross_entropy_with_logitssparse_softmax_cross_entropy_with_logitsbinary_cross_entropysigmoid_cross_entropy参考文档参考文档参考文档L1、L2、smooth L1 Losssoftmax..._smooth_l1_loss公式

PAT 乙级 1017 (方法 + 代码)_pat 1017乙-程序员宅基地

文章浏览阅读462次。1017 A除以B (20 分)本题要求计算 A/B,其中 A 是不超过 1000 位的正整数,B 是 1 位正整数。你需要输出商数 Q 和余数 R,使得 A=B×Q+R 成立。输入格式:输入在一行中依次给出 A 和 B,中间以 1 空格分隔。输出格式:在一行中依次输出 Q 和 R,中间以 1 空格分隔。输入样例:123456789050987654321 7输出样例:17636..._pat 1017乙