C#Dapper 超全详细使用教程(从入门到进阶)
C# Dapper 超全详细使用教程(从入门到进阶)
Dapper 是一款专为.NET设计的轻量级、高性能ORM(对象关系映射)框架,核心是扩展 ADO.NET 的 IDbConnection 接口,摒弃了复杂的配置和冗余的上下文管理,以极简的API封装原生SQL操作,性能接近手写ADO.NET,同时兼顾开发效率,是.NET项目中高频使用的数据持久化框架。本文将从基础概念、环境搭建、核心原理、基础CRUD、高级功能、最佳规范、优缺点等方面,全方位讲解Dapper的完整使用方案。
一、Dapper 核心基础介绍
1.1 核心原理
Dapper 基于 ADO.NET 底层封装,通过扩展方法增强 IDbConnection 接口能力,核心工作流程简单高效:
-
建立数据库连接:依托原生ADO.NET的IDbConnection接口创建数据库连接;
-
执行SQL语句:通过Dapper封装的扩展方法执行原生SQL或存储过程;
-
自动结果映射:将数据库查询结果集自动映射为C#实体对象或集合。
其高性能的核心原因:无复杂的实体跟踪、无需动态生成SQL、内置SQL查询计划缓存,最大程度减少性能开销。
1.2 Dapper 与主流数据库框架对比
为清晰区分各框架适用场景,以下是Dapper与EF、NHibernate、原生ADO.NET的特性对比:
| 特性 | Dapper | Entity Framework | NHibernate | ADO.NET |
|---|---|---|---|---|
| 性能 | 极高(接近原生) | 中等 | 中等 | 极高 |
| 易用性 | 高、API简洁 | 高、开箱即用 | 中等、配置繁琐 | 低、代码冗余 |
| 实体映射能力 | 基础强类型映射 | 丰富、全自动映射 | 丰富、全自动映射 | 无、手动映射 |
| 学习曲线 | 极低 | 中等 | 较高 | 低 |
| 事务支持 | 完整支持 | 完整支持 | 完整支持 | 原生支持 |
| LINQ支持 | 不支持 | 全面支持 | 全面支持 | 不支持 |
| 配置灵活性 | 极高、完全掌控SQL | 中等、封装度高 | 高、自定义性强 | 极高 |
二、环境准备与基础配置
2.1 安装Dapper NuGet包
项目使用Dapper前,必须安装官方NuGet包,提供三种安装方式:
-
Visual Studio可视化安装:右键项目 → 管理NuGet程序包 → 搜索「Dapper」安装;
-
包管理器控制台:
Install-Package Dapper; -
.NET CLI命令:
dotnet add package Dapper。
2.2 引入核心命名空间
以SQL Server为例,需引入以下必备命名空间,其他数据库需替换对应连接命名空间:
using System.Data; // 数据库操作核心接口
using System.Data.SqlClient; // SQL Server连接专属命名空间
using Dapper; // Dapper核心扩展命名空间
补充:MySQL对应命名空间为 MySqlConnector,PostgreSQL对应 Npgsql。
2.3 数据库连接配置
Dapper无连接池封装,完全依赖原生IDbConnection,标准使用方式为静态连接字符串+using自动释放连接,避免资源泄露:
// 数据库连接字符串(根据自身数据库配置修改)
private static readonly string _connectionString =
"Server=你的服务器名;Database=你的数据库名;Uid=用户名;Pwd=密码;TrustServerCertificate=True;";
// 标准连接使用模板
using (IDbConnection dbConnection = new SqlConnection(_connectionString))
{
dbConnection.Open(); // 显式打开连接(可控性更强,推荐使用)
// 所有数据库操作代码写在此代码块中
}
三、Dapper 基础CRUD操作(核心入门)
Dapper核心方法分为两类:Query系列(查询)、Execute(增删改),全程支持参数化查询,杜绝SQL注入。
3.1 定义对应数据库实体类
实体类字段建议与数据库表字段一致,字段不一致时可通过[Column("数据库字段名")] 特性映射:
public class User
{
public int Id { get; set; } // 主键ID
public string UserName { get; set; }// 用户名
public int Age { get; set; } // 年龄
public DateTime CreateTime { get; set; } // 创建时间
}
3.2 查询操作(单条/多条)
3.2.1 查询多条数据
使用 Query<T>() 方法,返回实体集合:
/// <summary>
/// 查询所有用户
/// </summary>
public List<User> GetAllUsers()
{
using (IDbConnection db = new SqlConnection(_connectionString))
{
db.Open();
string sql = "SELECT Id, UserName, Age, CreateTime FROM Users;";
// 自动映射为User实体列表
List<User> userList = db.Query<User>(sql).ToList();
return userList;
}
}
3.2.2 查询单条数据
使用 QueryFirstOrDefault<T>() 方法,无数据返回null,支持参数化查询:
/// <summary>
/// 根据ID查询单个用户
/// </summary>
public User GetUserById(int userId)
{
using (IDbConnection db = new SqlConnection(_connectionString))
{
db.Open();
// @Id为参数占位符,Dapper自动映射匿名对象参数
string sql = "SELECT Id, UserName, Age, CreateTime FROM Users WHERE Id = @Id;";
User user = db.QueryFirstOrDefault<User>(sql, new { Id = userId });
return user;
}
}
3.3 插入操作
使用 Execute() 方法,返回受影响的数据库行数,支持实体对象自动参数映射:
/// <summary>
/// 新增用户数据
/// </summary>
public int InsertUser(User newUser)
{
using (IDbConnection db = new SqlConnection(_connectionString))
{
db.Open();
string sql = @"INSERT INTO Users (UserName, Age, CreateTime)
VALUES (@UserName, @Age, @CreateTime);";
// 直接传入实体对象,自动匹配参数
int affectedRows = db.Execute(sql, newUser);
return affectedRows;
}
}
3.4 更新操作
同样使用 Execute() 方法,根据条件更新数据:
/// <summary>
/// 更新用户信息
/// </summary>
public int UpdateUser(User updateUser)
{
using (IDbConnection db = new SqlConnection(_connectionString))
{
db.Open();
string sql = @"UPDATE Users
SET UserName = @UserName, Age = @Age
WHERE Id = @Id;";
int affectedRows = db.Execute(sql, updateUser);
return affectedRows;
}
}
3.5 删除操作
通过 Execute() 实现条件删除,支持匿名对象传参:
/// <summary>
/// 根据ID删除用户
/// </summary>
public int DeleteUser(int userId)
{
using (IDbConnection db = new SqlConnection(_connectionString))
{
db.Open();
string sql = "DELETE FROM Users WHERE Id = @Id;";
int affectedRows = db.Execute(sql, new { Id = userId });
return affectedRows;
}
}
3.6 存储过程调用
Dapper支持直接调用数据库存储过程,只需指定命令类型为存储过程:
using (IDbConnection db = new SqlConnection(_connectionString))
{
// 调用名为GetStudentById的存储过程,传入参数
var result = db.Query<User>("GetUserById",
new { Id = 1 },
commandType: CommandType.StoredProcedure).FirstOrDefault();
}
四、Dapper 高级进阶功能
除基础CRUD外,Dapper支持多表映射、事务、批量操作、动态查询等复杂场景,满足企业级开发需求。
4.1 多表关联映射(一对一/一对多)
支持多表联查,将多表结果自动映射到嵌套实体,通过 splitOn 指定分割字段:
// 学生实体(嵌套班级实体)
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public Class Class { get; set; }
}
// 班级实体
public class Class
{
public int Id { get; set; }
public string ClassName { get; set; }
}
// 多表联查映射
string sql = "SELECT * FROM Students s INNER JOIN Classes c ON s.ClassId = c.Id";
var studentDict = new Dictionary<int, Student>();
using (IDbConnection db = new SqlConnection(_connectionString))
{
var studentList = db.Query<Student, Class, Student>(sql,
(student, cls) =>
{
student.Class = cls;
return student;
}, splitOn: "Id").Distinct().ToList();
}
4.2 事务处理(保证数据一致性)
Dapper完全兼容ADO.NET事务,支持多操作原子执行,要么全部成功,要么全部回滚:
using (IDbConnection db = new SqlConnection(_connectionString))
{
db.Open();
// 开启事务
using (var transaction = db.BeginTransaction())
{
try
{
// 执行新增
string insertSql = "INSERT INTO Students (Name, Age) VALUES (@Name, @Age)";
db.Execute(insertSql, new { Name = "John", Age = 22 }, transaction);
// 执行更新
string updateSql = "UPDATE Students SET Age = @Age WHERE Name = @Name";
db.Execute(updateSql, new { Age = 23, Name = "John" }, transaction);
// 提交事务
transaction.Commit();
}
catch
{
// 异常回滚
transaction.Rollback();
}
}
}
4.3 批量数据操作
Dapper支持直接传入实体集合,一次性完成批量新增/修改,性能高效:
using (IDbConnection db = new SqlConnection(_connectionString))
{
string sql = "INSERT INTO Students (Name, Age) VALUES (@Name, @Age)";
// 实体集合批量插入
var studentList = new List<Student>
{
new Student { Name = "John", Age = 22 },
new Student { Name = "Jane", Age = 24 },
new Student { Name = "Mark", Age = 26 }
};
// 批量执行,无需循环调用
db.Execute(sql, studentList);
}
4.4 动态对象查询
适用于查询结果结构不固定、无需定义实体类的场景,使用dynamic动态接收数据:
using (IDbConnection db = new SqlConnection(_connectionString))
{
string sql = "SELECT Name, Age FROM Students";
// 动态对象接收结果
var studentList = db.Query<dynamic>(sql).ToList();
foreach (var student in studentList)
{
Console.WriteLine($"姓名:{student.Name},年龄:{student.Age}");
}
}
4.5 查询缓存优化
Dapper内置查询缓冲机制,开启buffered可缓存查询结果,减少重复数据库请求开销(默认开启):
using (IDbConnection db = new SqlConnection(_connectionString))
{
string sql = "SELECT * FROM Students";
// 开启结果缓存,提升重复查询性能
var studentList = db.Query<Student>(sql, buffered: true).ToList();
}
五、跨数据库适配方案
Dapper 无数据库绑定特性,可无缝适配主流数据库,仅需替换NuGet包、连接对象、连接字符串:
-
MySQL:安装 MySqlConnector 包,使用 MySqlConnection 连接对象;
-
PostgreSQL:安装 Npgsql 包,使用 NpgsqlConnection 连接对象;
-
SQLite:安装 System.Data.SQLite 包,使用 SQLiteConnection 连接对象。
六、核心使用规范与最佳实践
-
强制使用参数化查询:所有动态条件必须使用 @参数占位符,杜绝字符串拼接SQL,彻底防止SQL注入;
-
using托管连接资源:所有IDbConnection对象必须包裹using语句,自动释放数据库连接,避免连接池泄露;
-
区分核心方法用途:Query系列方法仅用于查询,Execute方法统一用于增、删、改操作;
-
优先显式打开连接:手动调用Open(),相比Dapper自动打开连接,代码可控性更强,便于事务和批量操作;
-
规范实体映射:尽量保持实体属性与数据库字段一致,不一致时使用[Column]特性显式映射。
七、Dapper 优缺点总结与适用场景
7.1 核心优势
-
性能极致:无多余封装,性能接近原生ADO.NET,远超EF等重型框架;
-
轻量无侵入:体积小、零配置、学习成本极低,快速集成;
-
灵活性极强:完全掌控原生SQL,支持复杂查询、存储过程、批量操作;
-
安全性高:原生支持参数化查询,杜绝SQL注入风险;
-
兼容性好:支持所有主流关系型数据库,支持事务、缓存、多表映射。
7.2 局限性
-
不支持LINQ查询,需手动编写SQL,复杂查询需自行维护SQL语句;
-
无实体变化跟踪、级联操作等高级ORM功能;
-
自动映射能力有限,复杂多对多关系需手动配置映射逻辑。
7.3 适用场景
适合中小型项目、高性能数据接口、老旧项目改造、需要精准控制SQL的场景;不适合超大型复杂业务、依赖全自动ORM映射、需要大量LINQ查询的项目。
八、全文总结
Dapper 以“轻量、高效、灵活”为核心优势,平衡了原生ADO.NET的高性能和传统ORM的易用性。其核心使用逻辑简单:安装NuGet包→配置数据库连接→通过Query/Execute实现CRUD→借助高级功能适配复杂场景。在实际开发中,只要遵循参数化查询、using资源释放等规范,即可高效、稳定地完成各类数据库操作,是.NET生态中不可或缺的数据持久化工具。

浙公网安备 33010602011771号