Dapper:轻量级 .NET 数据访问层的高效实践

2025-07-16 08:30:11

前言

在 .NET 应用开发中,数据访问层的设计与实现对整体性能和可维护性具有决定性影响。传统的 ADO.NET 虽然灵活但代码冗长,而全功能 ORM(如 Entity Framework)则可能带来性能损耗和学习成本。Dapper 作为一款轻量级 ORM,凭借其极低的开销和简洁的 API 接口,成为众多开发者在需要直接控制 SQL 并兼顾性能的场景下的首选。

Dapper 简介

Dapper 是一个基于 ADO.NET 构建的微型对象关系映射器(Micro-ORM),其设计目标是为开发者提供一种既保留原生 SQL 控制力,又具备类型安全和便捷性的数据库访问方式。

不同于 Entity Framework 等重型 ORM,Dapper 不依赖复杂的模型生成机制或 LINQ 查询翻译,而是直接通过 SQL 字符串执行查询,并自动将结果映射到强类型对象或动态类型中。这种“少即是多”的设计理念使其在性能方面表现优异,同时保持了高度灵活性。

Dapper 支持主流数据库平台,包括 SQL Server、MySQL、PostgreSQL、SQLite 等,并可通过参数化查询防止 SQL 注入攻击,确保安全性。

安装与环境配置

Dapper 可通过 NuGet 快速集成到 .NET 项目中,支持多种运行时环境和开发框架。

使用 NuGet 安装

推荐使用 NuGet 包管理器进行安装:

dotnet add package Dapper

或者在 Visual Studio 中搜索 Dapper 并安装。

初始化数据库连接

Dapper 不管理数据库连接生命周期,因此你需要自行创建并维护 IDbConnection 实例。以下是一个典型的 SQL Server 连接示例:

using System.Data.SqlClient;

var connectionString = "Server=your_server;Database=your_db;User Id=sa;Password=your_pwd;";
using var connection = new SqlConnection(connectionString);
connection.Open();

对于 MySQL 或 PostgreSQL,只需更换对应的 ADO.NET 提供者即可,例如 MySqlConnectionNpgsqlConnection

核心功能与使用方式

Dapper 提供了一系列扩展方法,使数据库操作更加简洁且类型安全。

查询单个对象

使用 QueryFirstOrDefault<T> 方法可以查询返回单个对象:

var user = connection.QueryFirstOrDefault<User>(
    "SELECT * FROM Users WHERE Id = @Id", 
    new { Id = 1 });

上述代码中,@Id 是参数化查询的占位符,传入的对象属性名需与占位符名称一致。

查询多个对象

获取多个记录时,可以使用 Query<T> 方法:

var users = connection.Query<User>("SELECT * FROM Users").ToList();

该方法会自动将每行数据映射到 User 类实例。

动态类型查询

如果你希望不定义实体类也能处理结果,可以使用 dynamic 类型:

var result = connection.Query("SELECT Name, Age FROM Users").ToList();
foreach (var item in result)
{
    Console.WriteLine($"Name: {item.Name}, Age: {item.Age}");
}

插入数据

执行插入操作时,可以使用 Execute 方法:

var affectedRows = connection.Execute(
    "INSERT INTO Users (Name, Email) VALUES (@Name, @Email)",
    new { Name = "Tom", Email = "tom@example.com" });

返回值表示受影响的行数。

更新与删除

更新和删除操作同样使用 Execute 方法:

// 更新
var rowsUpdated = connection.Execute(
    "UPDATE Users SET Email = @Email WHERE Id = @Id",
    new { Email = "new_email@example.com", Id = 1 });

// 删除
var rowsDeleted = connection.Execute(
    "DELETE FROM Users WHERE Id = @Id",
    new { Id = 1 });

多结果集查询

Dapper 支持一次查询返回多个结果集,适用于复杂报表或聚合查询场景:

using var multi = connection.QueryMultiple("SELECT * FROM Users; SELECT * FROM Roles");
var users = multi.Read<User>().ToList();
var roles = multi.Read<Role>().ToList();

存储过程调用

调用存储过程也非常简单,只需指定命令类型:

var user = connection.QueryFirstOrDefault<User>(
    "GetUserById", 
    new { Id = 1 },
    commandType: CommandType.StoredProcedure);

事务处理

Dapper 支持事务操作,确保多个数据库操作的原子性:

using var transaction = connection.BeginTransaction();
try
{
    connection.Execute("INSERT INTO Logs (Message) VALUES ('Start')", transaction: transaction);
    connection.Execute("UPDATE Users SET Status = 1 WHERE Id = 1", transaction: transaction);
    transaction.Commit();
}
catch
{
    transaction.Rollback();
    throw;
}

映射规则与自定义处理

Dapper 默认根据字段名匹配实体属性名,若存在不一致情况,可以通过别名或自定义映射器进行调整。

自定义字段映射

你可以使用 SqlMapper.TypeMap 来注册自定义映射逻辑:

SqlMapper.SetTypeMap(
    typeof(User),
    new CustomPropertyTypeMap(
        typeof(User),
        (type, columnName) =>
            type.GetProperties().FirstOrDefault(prop => prop.Name.ToLower() == columnName.ToLower())));

复杂对象嵌套映射

当查询结果包含多个表的数据时,可以使用多映射函数来处理关联对象:

var sql = "SELECT * FROM Orders o JOIN Users u ON o.UserId = u.Id";
var orders = connection.Query<Order, User, Order>(
    sql,
    (order, user) =>
    {
        order.User = user;
        return order;
    },
    splitOn: "Id"
).ToList();

参数化查询与安全机制

Dapper 强烈推荐使用参数化查询,以防止 SQL 注入攻击。以下是一个安全写法示例:

var user = connection.Query<User>(
    "SELECT * FROM Users WHERE Name = @Name", 
    new { Name = userInput });

避免拼接字符串构造 SQL:

// ❌ 不推荐
string query = $"SELECT * FROM Users WHERE Name = '{userInput}'";

错误处理与日志输出

虽然 Dapper 本身不提供日志功能,但你可以结合日志框架(如 Serilog、NLog 或 Microsoft.Extensions.Logging)记录执行的 SQL 和异常信息。

例如,在捕获异常时输出 SQL:

try
{
    // 执行数据库操作
}
catch (Exception ex)
{
    logger.LogError(ex, "执行 SQL 出错:{sql}", sql);
    throw;
}

多数据库兼容性

Dapper 本身不绑定任何特定数据库引擎,只要提供符合 ADO.NET 规范的驱动,即可在不同数据库平台上运行。常见的适配器包括:

  • SQL Server: System.Data.SqlClient
  • MySQL: MySql.Data.MySqlClientMySqlConnector
  • PostgreSQL: Npgsql
  • SQLite: Microsoft.Data.Sqlite

你可以在不同数据库之间切换,只需修改连接字符串和提供对应数据库的连接对象。

DapperLib
一个.Net 数据库 ORM 框架
C#
Other
18.0 k