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 是一个非常好的选择。

相关推荐
小陈工2 小时前
Python Web开发入门(十七):Vue.js与Python后端集成——让前后端真正“握手言和“
开发语言·前端·javascript·数据库·vue.js·人工智能·python
科技小花6 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸6 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain6 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希7 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神7 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员7 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java7 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿7 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb
不知名的老吴7 小时前
Redis的延迟瓶颈:TCP栈开销无法避免
数据库·redis·缓存