DbContext 配置
这一页关注运行时入口:怎么连数据库、怎么暴露
DbSet<T>、怎么补充模型配置。
适用场景
- 已经定义好实体,准备让它真正接入数据库
- 想知道
onConfiguring和onModelCreating分别负责什么 - 需要统一配置日志、连接池、类型映射、默认跟踪策略
核心问题
DbContext 是 SqlSharp 的运行时中心。它至少做三件事:
- 暴露
DbSet<T> - 配置数据库连接
- 持有模型和变更跟踪上下文
有一个关键点需要先理解:SqlSharp 能自动生成 SQL。当你调用 ctx.add()、ctx.products.find()、ctx.saveChanges() 时,背后并没有人手工写 INSERT INTO ...——是框架根据实体元数据拼出来的。
要生成正确的 SQL,框架必须提前知道:
- 实体对应哪张表(
@Table/toTable()) - 字段对应哪个列(
@Column/hasColumnName()) - 哪个字段是主键(
@Key/hasKey()) - 哪些字段需要排除、哪些有并发保护
这些信息统称为模型元数据(Model Metadata)。DbContext 初始化时会扫描所有被引用的实体,构建这份元数据。只有通过 DbSet<T> 或 onModelCreating() 引用到的实体才会被扫描——打了 @Entity 但没在任何地方引用的类,框架看不见它,自然无法为它生成 SQL。
快速开始
先看最小配置:
public class AppDbContext <: DbContext {
public prop products: DbSet<Product> {
get() { set<Product>() }
}
public override func onConfiguring(b: DbContextOptionsBuilder): Unit {
b.useMysql("mariadb://localhost:3306?username=root&password=1024&database=mydb", "mariadb")
}
}定义好 DbContext 后,实体即可参与 CRUD,详见 定义实体。
核心概念
onConfiguring
这里负责运行时配置:数据源、SQL 日志、类型映射、连接池、默认跟踪策略等。
public override func onConfiguring(b: DbContextOptionsBuilder): Unit {
b.useMysql("mariadb://localhost:3306?username=root&password=1024&database=mydb", "mariadb")
b.logTo { sql, params => println("[SQL] ${sql}") }
let mapper = TypeMapper()
mapper.register<Address, String>(AddressJsonConverter())
b.useTypeMapper(mapper)
b.useQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
}PostgreSQL 连接示例:
b.usePostgres("postgres://test:1004@127.0.0.1:5432/cangjie_framework?sslmode=disable&TimeZone=Asia/Shanghai")多数据库按环境切换也是在这里处理:
public override func onConfiguring(b: DbContextOptionsBuilder): Unit {
if (env == "production") {
b.useMysql("mariadb://host1:3306?...", "mariadb")
} else {
b.usePostgres("postgres://test:1004@127.0.0.1:5432/devdb?sslmode=disable")
}
}SQL 日志
logTo 接收一个 (String, DbParameters) -> Unit 回调——每次框架生成 SQL 时,把 SQL 文本和参数传给你:
b.logTo { sql, params =>
println("=== SQL ===")
println(sql)
println("参数: ${params}")
}回调拿到的就是框架最终发给数据库的 SQL 和参数值,适合开发调试。可以按需筛选:
// 只看慢查询
b.logTo { sql, params =>
if (sql.startsWith("SELECT") && elapsed > 1000) {
println("[慢查询] ${sql}")
}
}
// 接入应用的 ILogger
b.logTo { sql, params =>
logger.debug("category: sql", sql)
}生产环境建议通过配置开关控制,避免日志量过大。
onModelCreating
这里负责模型层面的补充配置。适合放不方便写在注解里的内容,或者需要统一覆盖的规则。
protected override func onModelCreating(mb: ModelBuilder): Unit {
let entity = mb.entity<Product>()
entity.toTable("t_product")
entity.hasKey(["sku"])
entity.property("name").hasColumnName("p_name")
entity.property("version").isConcurrencyToken()
entity.ignore("tempField")
}注解和 FluentAPI 的关系
SqlSharp 支持两种配置方式:注解写在实体类上,FluentAPI 写在 onModelCreating 中。两者的优先级从低到高依次为:
约定默认值 < 注解 < FluentAPI| 配置项 | 默认值来源 | 注解 | FluentAPI |
|---|---|---|---|
| 表名 | DbSet<T> 属性名 | @Table["name"] | entity.toTable("name") |
| 列名 | 属性名 | @Column["name"] | .property("p").hasColumnName("name") |
| 主键 | _id + 整数类型 | @Key | entity.hasKey(["p"]) |
FluentAPI 在 onModelCreating 中最后执行,可以覆盖注解和默认值。具体的注解和 FluentAPI 用法对比见 定义实体 - 常见用法。
常见配置项
| 方法 | 说明 |
|---|---|
.useMysql(connectionString, driverName?) | MySQL / MariaDB |
.usePostgres(connectionString) | PostgreSQL |
.useOpenGauss(connectionString) | OpenGauss |
.useDatasource(connectionString, driverName) | 其他已注册驱动 |
.logTo { sql, params => ... } | 输出 SQL 日志 |
.useTypeMapper(mapper) | 注册类型映射 |
.usePooling(options?) | 连接池配置 |
.useQueryTrackingBehavior(behavior) | 默认跟踪策略 |
与其他模块组合
生产建议
- 连接字符串、日志开关、连接池参数尽量统一收敛到配置系统,不要散落在业务代码里
- 约定能表达的规则优先用约定,确实需要覆盖时再上 FluentAPI
- 如果系统读多写少,可以考虑默认
NoTracking,在需要更新的查询处显式开启跟踪