Dapper

发布于:2024-12-22 ⋅ 阅读:(14) ⋅ 点赞:(0)

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 中,打开包管理器控制台并运行以下命令:

dotnet add package Dapper

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

<PackageReference Include="Dapper" Version="2.0.123" />

基本用法

1. 查询单个对象

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

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>:执行查询并返回第一个匹配的结果,如果没有任何结果则返回默认值(null 或 default(T))。
  • @Id:参数化查询,防止 SQL 注入攻击。
2. 查询多个对象

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

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 方法来执行这些操作:

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. 更新数据

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

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. 删除数据

删除操作也非常简单:

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 方法来处理这种情况:

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 两个表,并且你想查询每个用户的订单信息:

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 方法来启动一个事务,并在提交或回滚时进行控制:

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. 批量操作对于批量插入或更新操作,可以使用 ExecuteBatch 或 BulkCopy 等方法来减少数据库往返次数。
  3. 异步编程尽量使用异步方法(如 QueryAsyncExecuteAsync)来避免阻塞主线程,特别是在 Web 应用程序中。

总结

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