类型映射
这一页关注业务类型和数据库存储类型之间的转换,例如值对象、JSON 字段、自定义枚举封装。
适用场景
- 实体字段不是数据库原生标量类型
- 需要把对象序列化后存到字符串或 JSON 列
- 想让查询、参数绑定、更新都共用同一套转换规则
核心问题
SqlSharp 通过 TypeMapper 和 ValueConverter 管理自定义类型映射。
核心思想是:
- 业务代码使用领域类型
- 持久化时转换成数据库能存的类型
- 查询回来时再转换回业务类型
快速开始
cangjie
import sqlsharp.converters.*
@Serialization
public class Address {
private var _city: String = ""
private var _street: String = ""
}
public class AddressJsonConverter <: ValueConverter<Address, String> {
public override func convertToProvider(value: Address): String {
JsonSerializer.serializeObject(value)
}
public override func convertFromProvider(value: String): Address {
JsonSerializer.deserializeObject<Address>(value)
}
}在 DbContext 里注册:
cangjie
public override func onConfiguring(b: DbContextOptionsBuilder): Unit {
let mapper = TypeMapper()
mapper.register<Address, String>(AddressJsonConverter())
b.useTypeMapper(mapper)
}核心概念
注册后,这个转换会同时参与:
- 实体查询
- DTO 查询
- SQL 参数绑定
- 更改跟踪
executeScalar<T>()
这意味着类型映射一旦定义好,就不需要在每个查询里重复手工转换。
常见用法
JSON 字段映射
最常见的场景是把对象序列化存到 JSON 列:
cangjie
// 实体定义
@Entity
@Serialization
public class User {
private var _id: Int64 = 0
private var _address: Address = Address()
}
// 注册转换器
public override func onConfiguring(b: DbContextOptionsBuilder): Unit {
let mapper = TypeMapper()
mapper.register<Address, String>(AddressJsonConverter())
b.useTypeMapper(mapper)
}
// 查询时自动反序列化
let user = ctx.users.find([Int64(1)]).getOrThrow()
let city = user.address.city // 直接访问领域对象数组字段映射
cangjie
public class TagsConverter <: ValueConverter<ArrayList<String>, String> {
public override func convertToProvider(value: ArrayList<String>): String {
value.join(",")
}
public override func convertFromProvider(value: String): String {
value.split(",")
}
}
mapper.register<ArrayList<String>, String>(TagsConverter())与其他模块组合
- 映射注册入口在 DbContext 配置
- 手写 SQL 和
Queryable都会复用这套转换规则 - 如果类型还要参与序列化映射,本身仍应具备相应的序列化能力
生产建议
- 先明确数据库实际存什么,再设计转换器
- 转换器逻辑尽量保持纯粹,不要混入业务判断
- JSON 存储方便,但也要评估查询能力和索引能力
常见问题
转换器能同时用于读写吗?
能。ValueConverter<TModel, TProvider> 同时定义了 convertToProvider(写)和 convertFromProvider(读),注册一次同时覆盖查询和写入。
JSON 字段能参与 WHERE 查询吗?
能,但取决于数据库的 JSON 函数支持。例如 MySQL 的 JSON_EXTRACT、MariaDB 的 JSON_VALUE 可以在手写 SQL 中使用。Queryable 的 whereIf 无法直接操作 JSON 内部字段,这种情况切到 手写 SQL。