Dapper

Dapper 简介

Dapper 是一个轻量级的 ORM(对象关系映射)库,由 Stack Overflow 团队开发并维护。它旨在提供高效的数据库访问,同时保持代码的简洁性和性能。Dapper 的核心功能是将 SQL 查询结果自动映射到 C# 对象,而不需要编写大量的手动映射代码。

为什么选择 Dapper?
  1. 轻量级:Dapper 只是一个小型的库,不会像 Entity Framework 或 NHibernate 那样引入大量依赖或复杂的配置。
  2. 高性能:Dapper 的性能非常接近直接使用 ADO.NET,因为它只做了一层简单的封装,没有额外的开销。
  3. 灵活性:Dapper 允许你编写原始 SQL 查询,提供了对数据库的完全控制,同时也支持参数化查询和多结果集处理。
  4. 简单易用:Dapper 的 API 非常简单,学习曲线低,适合快速开发和原型设计。

安装 Dapper

你可以通过 NuGet 包管理器安装 Dapper。在 Visual Studio 中,打开包管理器控制台并运行以下命令:

cs 复制代码
dotnet add package Dapper

或者,在项目文件中添加以下依赖项:

cs 复制代码
<PackageReference Include="Dapper" Version="2.0.123" />

基本用法

1. 查询单个对象

假设你有一个 User 类,并且你想从数据库中查询单个用户:

cs 复制代码
public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

using (var connection = new SqliteConnection(_connectionString))
{
    var user = await connection.QueryFirstOrDefaultAsync<User>("SELECT * FROM Users WHERE Id = @Id", new { Id = 1 });
    Console.WriteLine($"User: {user.Name}, Email: {user.Email}");
}
  • QueryFirstOrDefaultAsync<T>:执行查询并返回第一个匹配的结果,如果没有任何结果则返回默认值(nulldefault(T))。
  • @Id:参数化查询,防止 SQL 注入攻击。
2. 查询多个对象

如果你想查询多个用户,可以使用 QueryAsync<T>

cs 复制代码
using (var connection = new SqliteConnection(_connectionString))
{
    var users = await connection.QueryAsync<User>("SELECT * FROM Users");
    foreach (var user in users)
    {
        Console.WriteLine($"User: {user.Name}, Email: {user.Email}");
    }
}
  • QueryAsync<T>:执行查询并返回一个 IEnumerable<T>,表示查询结果的集合。
3. 插入数据

Dapper 也支持插入、更新和删除操作。你可以使用 ExecuteAsync 方法来执行这些操作:

cs 复制代码
using (var connection = new SqliteConnection(_connectionString))
{
    var newUser = new User { Name = "John Doe", Email = "john.doe@example.com" };
    var rowsAffected = await connection.ExecuteAsync("INSERT INTO Users (Name, Email) VALUES (@Name, @Email)", newUser);
    Console.WriteLine($"Rows affected: {rowsAffected}");
}
  • ExecuteAsync:执行非查询语句(如 INSERTUPDATEDELETE),并返回受影响的行数。
4. 更新数据

更新操作与插入类似,只需提供要更新的条件:

cs 复制代码
using (var connection = new SqliteConnection(_connectionString))
{
    var updatedUser = new { Id = 1, Name = "Jane Doe", Email = "jane.doe@example.com" };
    var rowsAffected = await connection.ExecuteAsync("UPDATE Users SET Name = @Name, Email = @Email WHERE Id = @Id", updatedUser);
    Console.WriteLine($"Rows affected: {rowsAffected}");
}
5. 删除数据

删除操作也非常简单:

cs 复制代码
using (var connection = new SqliteConnection(_connectionString))
{
    var rowsAffected = await connection.ExecuteAsync("DELETE FROM Users WHERE Id = @Id", new { Id = 1 });
    Console.WriteLine($"Rows affected: {rowsAffected}");
}
6. 多结果集处理

Dapper 支持多结果集查询,即一次查询返回多个表的数据。你可以使用 QueryMultiple 方法来处理这种情况:

cs 复制代码
using (var connection = new SqliteConnection(_connectionString))
{
    using (var multi = await connection.QueryMultipleAsync("SELECT * FROM Users; SELECT * FROM Orders"))
    {
        var users = await multi.ReadAsync<User>();
        var orders = await multi.ReadAsync<Order>();

        foreach (var user in users)
        {
            Console.WriteLine($"User: {user.Name}");
        }

        foreach (var order in orders)
        {
            Console.WriteLine($"Order: {order.OrderId}");
        }
    }
}
  • QueryMultipleAsync:执行多结果集查询,并返回一个 SqlMapper.GridReader 对象,可以通过 ReadAsync<T> 方法逐个读取每个结果集。

高级功能

1. 自动映射复杂对象

Dapper 支持自动映射复杂对象,包括嵌套对象和多个表的联合查询。例如,假设你有 UserOrder 两个表,并且你想查询每个用户的订单信息:

cs 复制代码
public class UserWithOrders
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<Order> Orders { get; set; }
}

public class Order
{
    public int OrderId { get; set; }
    public DateTime OrderDate { get; set; }
}

using (var connection = new SqliteConnection(_connectionString))
{
    var sql = @"
        SELECT u.Id, u.Name, o.OrderId, o.OrderDate
        FROM Users u
        LEFT JOIN Orders o ON u.Id = o.UserId";

    var result = await connection.QueryAsync<User, Order, UserWithOrders>(
        sql,
        (user, order) =>
        {
            var userWithOrders = new UserWithOrders
            {
                Id = user.Id,
                Name = user.Name,
                Orders = new List<Order>()
            };

            if (order != null)
            {
                userWithOrders.Orders.Add(order);
            }

            return userWithOrders;
        },
        splitOn: "OrderId"
    );

    // 使用 LINQ 进行分组
    var usersWithOrders = result.GroupBy(x => x.Id)
                                .Select(g => new UserWithOrders
                                {
                                    Id = g.Key,
                                    Name = g.First().Name,
                                    Orders = g.SelectMany(x => x.Orders).ToList()
                                })
                                .ToList();

    foreach (var user in usersWithOrders)
    {
        Console.WriteLine($"User: {user.Name}");
        foreach (var order in user.Orders)
        {
            Console.WriteLine($"  Order: {order.OrderId}, Date: {order.OrderDate}");
        }
    }
}
  • QueryAsync<T1, T2, TReturn>:用于映射多个表的联合查询。splitOn 参数指定了如何区分不同的表(通常是主键列)。
  • GroupBy:用于将多个结果集分组为单个对象。
2. 事务支持

Dapper 也支持事务操作。你可以使用 BeginTransaction 方法来启动一个事务,并在提交或回滚时进行控制:

cs 复制代码
using (var connection = new SqliteConnection(_connectionString))
{
    using (var transaction = await connection.BeginTransactionAsync())
    {
        try
        {
            // 执行插入操作
            await connection.ExecuteAsync("INSERT INTO Users (Name, Email) VALUES (@Name, @Email)", new { Name = "John Doe", Email = "john.doe@example.com" }, transaction);

            // 执行另一个插入操作
            await connection.ExecuteAsync("INSERT INTO Orders (UserId, OrderDate) VALUES (@UserId, @OrderDate)", new { UserId = 1, OrderDate = DateTime.Now }, transaction);

            // 提交事务
            await transaction.CommitAsync();
        }
        catch (Exception ex)
        {
            // 回滚事务
            await transaction.RollbackAsync();
            throw;
        }
    }
}

性能优化

Dapper 的性能非常接近原生 ADO.NET,因为它只做了一层简单的封装。为了进一步提高性能,你可以考虑以下几点:

  1. 使用缓存 :Dapper 提供了内置的查询计划缓存机制,可以在多次执行相同的查询时提高性能。
  2. 批量操作 :对于批量插入或更新操作,可以使用 ExecuteBatchBulkCopy 等方法来减少数据库往返次数。
  3. 异步编程 :尽量使用异步方法(如 QueryAsyncExecuteAsync)来避免阻塞主线程,特别是在 Web 应用程序中。

总结

Dapper 是一个非常强大且灵活的轻量级 ORM 库,适合需要高效数据库访问的应用程序。它提供了简单易用的 API,支持多种数据库类型(如 SQLite、SQL Server、MySQL 等),并且能够很好地与现有的 ADO.NET 代码集成。如果你希望在保持高性能的同时简化数据库操作,Dapper 是一个非常好的选择。

相关推荐
漫随流水几秒前
旅游推荐系统(view.py)
前端·数据库·python·旅游
ego.iblacat11 分钟前
MySQL 服务基础
数据库·mysql
Maverick062 小时前
Oracle Redo 日志操作手册
数据库·oracle
攒了一袋星辰2 小时前
高并发强一致性顺序号生成系统 -- SequenceGenerator
java·数据库·mysql
W.D.小糊涂2 小时前
gpu服务器安装windows+ubuntu24.04双系统
c语言·开发语言·数据库
云贝教育-郑老师2 小时前
【OceanBase 的多租户架构是怎样的?有什么优势?】
数据库·oceanbase
顶点多余3 小时前
使用C/C++语言链接Mysql详解
数据库·c++·mysql
xiaokangzhe3 小时前
MySQL 数据库操作
数据库·oracle
发际线还在4 小时前
互联网大厂Java三轮面试全流程实战问答与解析
java·数据库·分布式·面试·并发·系统设计·大厂
小王不爱笑1325 小时前
MyBatis 执行流程源码级深度解析:从 Mapper 接口到 SQL 执行的全链路逻辑
数据库·sql·mybatis