目录

介绍

为什么使用Dapper?

实现

配置Dapper以在ASP.NET应用程序中使用

管理数据库连接

管理SQL语句

示例应用程序

例 1

例 2

结论

经验 教训


  • 下载源代码 - 71.4 KB

介绍

Dapper是一种流行的SQL数据库映射器。通常,它将表行中的列字段映射到C#类实例中的属性以及从中映射属性。在数据管理的三层模型中,Dapper位于中间层,它从上层视图或表示层获取数据,并以数据库可以操作的形式将其呈现给较低的数据层。以类似的方式,它从数据库中获取数据,并以视图可以使用的形式将其呈现给上层。

为什么使用Dapper?

它易于使用,轻量级(47K)且速度快——大约是实体框架速度的两倍。作者是StackOverflow的一个团队,他们维护它并使用它来访问他们庞大的数据库。它并不打算替代实体框架,该框架是一个极好的对象关系映射器(ORM),具有您可能希望的所有功能,但是许多用户难以控制它,结果是采取不需要旅行的路线,并且携带的行李永远不会被打开包装。有了Dapper,您就坐在驾驶座上了。你引导它去哪里,并确定它到达那里时做什么。

实现

Dapper在 GitHub 上作为开源提供,并作为 Nuget 包提供。它不作为一个单独的实体存在,它是作为扩展方法的集合实现的,这些方法实际上扩展了IDbConnection接口。这类似于system.Linq扩展IEnumerable<T>的方式。Dapper查询的常用格式是将SQL语句作为string与语句所需的任何参数(表示为匿名类型的成员)结合使用。类似的东西。

int id = 7;
string sql = @"Select *from dbo.Employees where EmployeeID=@Id;";
using IDbConnection connection = _connectionCreator.CreateConnection();
var employee = await connection.QueryFirstOrDefaultAsync<Employee>(sql,new{Id=id});

在这里,SQL语句是从Employees表中EmployeeID列等于输入参数Id的行中选择所有列字段。“@”符号标识语句所需的输入参数。使用QueryFirstOrDefaultAsync<T>泛型方法是因为EmployeeID是主键,因此只有一条记录要搜索。匿名类型的成员名称与SQL语句引用的输入参数的名称匹配,并将其设置为局部变量id的值。Dapper将查询的输出映射到type T的实例。在此示例中,type T这被定义为Employee类。这是基本设置,还有其他Query方法从数据库请求数据,以及将命令传递到数据库的Execute方法,例如Insert、Delete和Update。通常有同一方法的异步和同步版本。Learn Dapper网站和 GitHub 上的Dapper Readme.md 文件有许多 Dapper 的优秀示例。

配置Dapper以在ASP.NET应用程序中使用

管理数据库连接

需要先打开数据库连接,然后才能使用,然后在查询完成后立即关闭和释放。这意味着每个Dapper扩展方法都有一定数量的连接管理工作。还需要引用特定于数据库服务器的IDbConnection实例。因此,这里可能存在大量代码重复,并且依赖于进行数据库调用的每个方法的所选IDbConnection类型。此问题的解决方案是将Dapper方法封装在IDatabaseContext类中,以便使用此类的任何内容都不需要知道Dapper或数据库连接。下面是调用Dapper的ExecuteAsync方法的IDatabaseContext方法的示例。

public async Task<T> QueryFirstOrDefaultAsync<T>(string sql,object? parameters = null,CommandType? commandType = null){using IDbConnection connection = _connectionCreator.CreateConnection();var result = await connection.QueryFirstOrDefaultAsync<T>(sql, parameters,commandType: commandType);return result;}

该ConnectionCreator.CreateConnection方法是一个工厂方法,它返回Connection的新实例。

public class MsSqlConnectionCreator : IConnectionCreator
{protected ServerOptions _serverOptions;public MsSqlConnectionCreator(IOptions<ServerOptions> serverOptionsSnapshot){_serverOptions = serverOptionsSnapshot.Value;}public  IDbConnection CreateConnection(){var connectionString = _serverOptions.MsSql;return new SqlConnection(connectionString);}
}

DatabaseContext从注入到其构造函数中的IOptions<T>泛型类型的实例中获取数据库连接字符串。

public SqlServerContext(IOptions<ServerOptions> serverOptionsSnapshot){_serverOptions = serverOptionsSnapshot.Value;_connectionString = _serverOptions.MsSql;}    

此技术被认为比传入配置管理器并使用管理器读取连接的替代选择更可取。它的优点是将ConfigurationManager作用域限制在Program.csStartup.cs中的其他应用程序构建器。appsettings.json 中ConnectionStrings部分的成员值在运行时绑定到单一实例ServerOptions类。

"ConnectionStrings": {"MsSql": "Data Source=(localdb)\\ProjectModels;Initial Catalog=Northwind;Integrated Security=True","MySql": "Server=127.0.0.1;user ID=root; Database=northwind; Password=Pa$$w0rd"},
....

该ServerOptions类具有几个与ConnnectionStrings部分中的名称匹配的属性。

public class ServerOptions
{//ConnectionStrings is not mapped, //it's used to avoid a magic string when referencing// the appsettings "ConnectionStrings" sectionpublic const string ConnectionStrings = "ConnectionStrings";public string MsSql { get; set; } = string.Empty;public string MySql { get; set; } = string.Empty;
}

绑定在Program.cs中设置。

var section = builder.Configuration.GetSection("ConnectionStrings");
builder.Services.Configure<ServerOptions>(section);

管理SQL语句

拥有一个实现IDataAccess接口的类可以解决很多问题,但仍然需要由在表示层中运行的服务发出SQL语句。SQL语句基本上是数据库服务器的数据管理指令,理想情况下,应该位于数据库内部。实现此目的的方法是使用存储过程。存储过程是驻留在数据库中的预编译SQL语句。在 SQL Server对象资源管理器中,它们位于数据库的可编程性文件夹中。下面演示如何从罗斯文示例数据库调用CustOrderHist存储过程。

string customerID = "ANTON";//input param
var results = await _databaseContext.QueryAsync<ProductSummary>(_storedProcedureId.CustomerOrderHistory,new { CustomerID = customerID }, commandType: CommandType.StoredProcedure);

通过使用命名参数初始化commandType参数。命名参数避免了必须为在所需参数之前排序的参数输入大量null值。过程名称作为自定义StoredProcedureId类的属性传入。

public  string CustomerOrderHistory { get; } = "dbo.CustOrderHist";

Northwind的Orders表中有超过800条记录,但Dapper可以在眨眼间完成此过程。

示例应用程序

示例应用程序是使用该Northwind数据库的ASP.NET 7控制台应用。它需要更新 appsettings.json 文件中的连接字符串以指向数据库服务器的实例。这些示例将使用TSql或MySql语句运行,具体取决于所选的SQL Server。它们并不是确定的,大多数都是不言自明的,但有几个可能需要一些澄清。

例 1

此查询涉及两个类。该Order类对Orders表进行建模,该Employee类对Employees表进行建模。该Order类还具有引用Employees的表主键的外键,此外,它还具有引用Employee类实例的属性。

public class Order
{public int OrderID { get; set; }public string? CustomerID { get; set; }public int EmployeeID { get; set; }public DateTime OrderDate { get; set; }public int ShipperID { get; set; }public Employee? Employee { get; set; }
}

SQL语句在匹配EmployeeIDs时连接两个表,并按Employee的LastName并且之后按FirstName对查询进行排序。

string sql = @"select o.EmployeeID,o.OrderId,e.EmployeeID,e.FirstName,e.LastNamefrom dbo.Orders oinner join dbo.Employees eon o.EmployeeID  = e.EmployeeIDorder by e.LastName, e.FirstName";

Dapper获取此查询的结果并将其映射到Order项集合。

var employeeOrders= await _databaseContext.QueryAsync<Order, Employee>(sql,(order, employee) =>{order.Employee = employee;return order;}, splitOn: "EmployeeID");

为了使 Dapper 能够有效地映射,需要为其提供一个函数,该函数将类属性设置为实例并返回类实例。还需要告诉 Dapper 在查询返回的所有列中,与表相关的列结束和表中的列开始的位置。假定这是当遇到值为 “” 的列名时。但是,在这种情况下,相关标识列的名称是,因此需要将参数设置为该名称。OrderEmployeeEmployeeOrderOrdersEmployeesToUpper()IDEmployeeIDsplitOn

例 2

此示例包含一个SQL语句,该语句通常会导致异常,因为它具有一个集合作为输入参数,并且通常不允许使用参数集合。Dapper通过将集合解构为SQL解析器将接受的格式的一系列单个参数来规避该限制。该语句将该集合引用为@countries。局部变量countryArray使用匿名类型传递到QueryAsync方法中,其成员必须与引用的参数命名相同,并设置为局部数组实例。该查询获取数组中指定的四个国家/地区中每个国家/地区供应的产品总数。

string[] countryArray = new[] { "France", "Germany", "UK", "USA" };
string sql = @"Select Suppliers.Country As SuppliersCountry,COUNT(*) as ProductCountFrom Suppliers join Products on Suppliers.SupplierID=Products.SupplierIDwhere Suppliers.Country in @countriesGroup by Suppliers.CountryOrder by ProductCount Desc;";
var results = await _dba.QueryAsync<(string SuppliersCountry, int ProductCount)>(sql, new { countries = countryArray });

如果你不熟悉SQL,上面的语句可能看起来有点吓人。一个有用的提示是尝试从后到前阅读它。因此,从最后一个子句开始,输出按ProductCount降序排序。它仅按Suppliers.Country输入参数集合中Suppliers.Country存在的位置进行分组。在Suppliers.SupplierID等于Products.SupplierID时,通过将Suppliers表中的每一行连接到Products表中的匹配行来获得数据。所选的行和列输出将Suppliers.Country作为SuppliersCountry列的成员,并将该组中所有项目的计数作为ProductCount列的成员。在SQL中,分组表示为键/值对,其中值是聚合函数的结果,该聚合函数使用组的成员项集合作为输入参数。这是压缩到几行代码中的许多功能。SQL是编程语言的哥伦布;它比看起来更聪明。

结论

使用Dapper扩展方法作为数据库映射器是使用实体框架提供的类型的有用且有效的替代方法。在不需要实体框架的高级功能的情况下尤其如此。

经验 教训

重要的是,等待Dapper的所有async方法。简单地调用该方法并返回Task以便另一个方法可以await它,这样做并不是一个好主意。尽管该技术避免了与使用async关键字相关的开销,但它也会导致null引用异常。这些方法是从using语句中调用的,一旦返回未完成的Task方法,该using语句就会确保连接关闭,结果是Dapper保持高位和干燥。我发现这是艰难的。

https://www.codeproject.com/Articles/5351042/Dapper-The-Pocket-Rocket-Mapz

Dapper——袖珍火箭映射器相关推荐

  1. 【实战】文本驱动的StyleGAN2图像处理(二):潜码映射器(Latent Mapper)

    StyleCLIP项目由以色列的耶路撒冷希伯来大学.特拉维夫大学和Adobe研究所共同完成,它用对比语言-图像预训练(CLIP)模型的力量,为StyleGAN2 图像处理开发一个基于文本的输入界面,利 ...

  2. Nmap (网络映射器)好东西啊

    2019独角兽企业重金招聘Python工程师标准>>> Nmap  (网络映射器)是由 Gordon Lyon设计,用来探测计算机网络上的主机和服务的一种安全扫描器.为了绘制网络拓扑 ...

  3. Windows 7安装MySQL最后一步提示错误“mysql 终结点映射器中没有更多的终结点可用的” 解决方法...

    今天在Windows7系统安装MySQL5.5的时候,碰到错误提示"mysql 终结点映射器中没有更多的终结点可用的" 原因如下: 点击确认后,MySQL可以正常使用 转载于:ht ...

  4. 数据源架构模式之数据映射器

    http://lobert.iteye.com/blog/2102312 前面分别介绍了数据源架构模式之表数据入口.数据源架构模式之行和数据入口数据源架构模式之活动记录,相较于这三种数据源架构模式,数 ...

  5. SpringMVC - 非注解的处理器映射器和适配器

    为什么80%的码农都做不了架构师?>>>    一.非注解的处理器映射器 提供的处理器有两个属性.一个是id属性,一个是name属性.分别对应两种不同的映射器. <bean i ...

  6. mybatis映射器${}和#{}的区别

    mybatis映射器${}和#{}的区别 转载于:https://www.cnblogs.com/liyuchen/p/7850185.html

  7. 管理springmvc组件——前端控制器、控制器映射器和适配器、视图解析器、文件上传的、拦截器||消息转化

    管理springmvc组件 概述 在使用springmvc时要配置哪些东西 前端控制器 控制器映射器和适配器 映射器  Map<Set<String>,Object> Set& ...

  8. mybatis的mapper.xml文件中含有中文注释时运行出错,mybatis配置优化和别名优化 mybatis配置之映射器说明

    记录一个发现的小问题,刚刚在UserMapper.xml文件中有一段中文注释掉的内容: <!-- <resultMap id="Usermap" type=" ...

  9. VTK:标签放置映射器用法实战

    VTK:标签放置映射器用法实战 程序输出 程序完整源代码 程序输出 程序完整源代码 #include <vtkActor.h> #include <vtkActor2D.h> ...

最新文章

  1. 远程办公如何保持高效?这群开发者们是这样做的
  2. TMG 日志队列(Log Queue,扩展名为 .LLQ)持续增长或 TMG
  3. 初学FF(火狐)的扩展(Extensions)
  4. img元素高度多出来的几像素
  5. [MATLAB调试笔记]Update magnetic field in one step
  6. ClientScript.RegisterClientScriptBlock 不执行
  7. MyBatis常用配置解析-Properties标签
  8. 事件处理之二:点击事件监听器的五种写法
  9. 今年不容易,要懂得爱护自己
  10. android-短信验证功能,Android实现获取短信验证码的功能以及自定义GUI短信验证详解...
  11. python运行界面黑色,在Python中使用open执行轮廓检测后,如何使图像的背景变黑?...
  12. 【华为云技术分享】三大前端技术(React,Vue,Angular)探密(下)
  13. 获取时间差xx小时xx分钟前
  14. Python学习手册之Python异常和文件
  15. 在线客服系统代码安装 (附移动版APP下载)
  16. Android Studio创建app问题: Install repository and sync project等
  17. 皮卡丘(pikachu) 文件上传
  18. Maven安装配置详细教程
  19. 全等三角形的判定方法
  20. 应用再设计__Thanx

热门文章

  1. 【良品】运维实施工程师面试题
  2. 脸书研发新AI工具:让照片中闭眼的人重新睁眼
  3. 段路由SR(Segment Routing)是基于源路由理念而设计的在网络上转发数据包的一种技术架构
  4. LeNet识别自己的手写数字
  5. 三阶魔方还原方法(白色在上层先法)
  6. 知识付费社群运营怎么做?
  7. SparkMllib介绍
  8. 2020年第十一届java B组蓝桥杯省赛真题
  9. 如何做好沙漠旅游规划和沙漠旅游开发?
  10. Standard Templete Library —— Containers