Docker 化您的 Web API 与 SQL Server、Dapper 和 FluentMigrator
发布: (2025年12月7日 GMT+8 07:26)
4 min read
原文: Dev.to
Source: Dev.to
介绍
在第 1 和 2 部分,我们介绍了用于模式管理和 CI/CD 自动化的 FluentMigrator。在本部分,我们将 对整个堆栈进行 Docker 化——SQL Server、迁移以及基于 Dapper 的 Web API——从而只需一个命令即可启动完整的开发环境。
完整技术栈
| 组件 | 技术 | 目的 |
|---|---|---|
| 数据库 | SQL Server 2022 | 数据存储 |
| 迁移 | FluentMigrator | 架构版本管理 |
| 数据访问 | Dapper | 高性能 SQL 映射 |
| API | ASP.NET Core 8 | HTTP 端点 |
| 编排 | Docker Compose | 容器管理 |
我们要构建的内容
┌─────────────────────────────────────────────────────────────┐
│ docker compose up │
└─────────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ sqlserver│ │db-migrate│ │product‑api│
│ :1433 │ │ (runs │ │ :5050 │
│ │◄──│ once) │──►│ │
└──────────┘ └──────────┘ └──────────┘
│ │ │
└───────────────┴───────────────┘
│
productapi‑network
流程
- sqlserver 启动并等待健康状态。
- db‑migrate 运行 FluentMigrator 迁移(一次),随后退出。
- product‑api 仅在迁移成功后启动。
为什么要 Docker 化?
| 好处 | 描述 |
|---|---|
| 一键设置 | docker compose up – 完成 |
| 环境一致性 | 在你的机器、同事机器以及 CI/CD 中保持一致 |
| 无需本地安装 | 无需 SQL Server、SDK |
| 隔离 | 不会与其他项目冲突 |
| 近似生产环境 | 完全测试将要部署的内容 |
项目结构
ProductApi/
├── docker-compose.yml # Orchestrates everything
├── src/
│ ├── ProductWebAPI/
│ │ ├── Dockerfile # API container
│ │ ├── Controllers/
│ │ └── Services/
│ ├── ProductWebAPI.Database/
│ │ ├── Dockerfile # Migration runner
│ │ └── Migrations/
│ └── CommonComps/
│ ├── Models/ # Domain models
│ └── Repositories/ # Dapper implementations
快速回顾:本栈中的 Dapper
┌─────────────────────────────────────────────────────────────┐
│ ProductsController │
│ (HTTP endpoints) │
└─────────────────────────┬───────────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────────┐
│ ProductService │
│ (Business logic) │
└─────────────────────────┬───────────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────────┐
│ ProductRepository (Dapper) │
│ Write SQL → Get C# objects back │
└─────────────────────────┬───────────────────────────────────┘
│
┌─────────────────────────▼───────────────────────────────────┐
│ SQL Server (FluentMigrator‑managed) │
└─────────────────────────────────────────────────────────────┘
示例仓库
public class ProductRepository : IProductRepository
{
private readonly string _connectionString;
public ProductRepository(IConfiguration configuration)
{
_connectionString = configuration.GetConnectionString("DefaultConnection")
?? throw new ArgumentNullException("Connection string not found");
}
private IDbConnection CreateConnection() => new SqlConnection(_connectionString);
public async Task GetByIdAsync(int id)
{
const string sql = @"
SELECT p.*, c.*
FROM Products p
INNER JOIN Categories c ON p.CategoryId = c.Id
WHERE p.Id = @Id";
using var connection = CreateConnection();
var result = await connection.QueryAsync(
sql,
(product, category) => { product.Category = category; return product; },
new { Id = id },
splitOn: "Id"
);
return result.FirstOrDefault();
}
public async Task CreateAsync(Product product)
{
const string sql = @"
INSERT INTO Products (Name, SKU, Description, Price, CategoryId, IsActive, CreatedAt)
OUTPUT INSERTED.Id
VALUES (@Name, @SKU, @Description, @Price, @CategoryId, @IsActive, GETUTCDATE())";
using var connection = CreateConnection();
return await connection.ExecuteScalarAsync(sql, product);
}
}
Dapper 关键模式
QueryAsync– 返回集合。QueryFirstOrDefaultAsync– 返回单个项目或null。ExecuteScalarAsync– 返回单个值(例如插入的 ID)。ExecuteAsync– 返回受影响的行数。
为什么选择 Dapper?
- ⚡ 接近原始 ADO.NET 的性能。
- 💪 完全掌控 SQL。
- 📦 轻量级(没有沉重的 ORM 开销)。
步骤 1:Web API 的 Dockerfile
File: src/ProductWebAPI/Dockerfile
# Use the official .NET 8 SDK image for building
FROM mcr.microsoft.com/dotnet