Cangjie-SIG/fountain ID查询映射:IdQueryMapper主键查询
Cangjie-SIG/fountain ID查询映射:IdQueryMapper主键查询
痛点:主键查询的复杂性
在日常数据库操作中,主键查询是最常见且最频繁的操作之一。传统方式中,开发者需要手动编写SQL语句、处理结果集映射、处理空值异常等繁琐工作。特别是在仓颉语言(Cangjie)这种强类型语言中,类型安全和性能优化尤为重要。
你还在为这些问题烦恼吗?
- 手动编写重复的主键查询代码
- 处理复杂的结果集映射逻辑
- 担心类型转换错误和空指针异常
- 需要为不同的主键类型编写不同的查询逻辑
一文解决所有问题! 本文将深入解析Cangjie-SIG/fountain中的IdQueryMapper组件,让你掌握高效、安全的主键查询技术。
IdQueryMapper核心架构
IdQueryMapper是fountain ORM框架中的核心组件,专门用于处理基于主键的查询操作。它继承自FieldQueryMapper,提供了类型安全的主键映射能力。
类层次结构
核心特性
| 特性 | 描述 | 优势 |
|---|---|---|
| 类型安全 | 泛型参数ID和O确保编译时类型检查 | 避免运行时类型错误 |
| 自动映射 | 自动处理结果集到对象的映射 | 减少手动编码工作量 |
| 空值处理 | 内置Option类型处理空值情况 | 防止空指针异常 |
| 性能优化 | 缓存列信息和结果数据 | 提升查询性能 |
| 扩展性 | 支持各种主键数据类型 | 适应不同业务场景 |
核心API详解
构造函数
public class IdQueryMapper<ID, O> <: FieldQueryMapper<ID, O> where ID <: Hashable & Equatable<ID> {
public init(
dataType!: DataType = Int64DataType(false, 'id'),
putter!: (O, ID) -> Unit
) {
super(dataType: dataType, putter: putter)
}
}
参数说明:
dataType: 数据类型,默认为非空的Int64类型,列名为'id'putter: 设置器函数,用于将主键值设置到目标对象中
主要方法
1. populate方法 - 结果集填充
public func populate(result: QueryResultWrap, o: O): O {
if (let Some(id) <- super.get<ID>(result)) {
putter(o, id)
}
o
}
该方法从查询结果中提取主键值,并通过putter函数设置到目标对象中。
2. id方法 - 直接获取主键值
public func id(result: QueryResultWrap): ID {
super.get<ID>(result).getOrThrow()
}
直接返回查询结果中的主键值,如果值为空则抛出异常。
3. isId属性 - 标识为主键映射器
protected prop isId: Bool {
get() {
true
}
}
标识该映射器为主键映射器,用于QueryMappers中的特殊处理。
数据类型支持
IdQueryMapper支持多种数据类型,通过DataType体系提供类型安全的映射:
| 数据类型类 | 对应Cangjie类型 | 描述 |
|---|---|---|
| Int64DataType | Int64 | 64位整数,常用作主键 |
| UInt64DataType | UInt64 | 无符号64位整数 |
| Int32DataType | Int32 | 32位整数 |
| StringDataType | String | 字符串类型主键 |
| UUIDDataType | UUID | UUID类型主键 |
数据类型使用示例
// 使用Int64作为主键类型
let idMapper = IdQueryMapper<Int64, User>(
dataType: Int64DataType(false, 'user_id'),
putter: { user, id => user.id = id }
)
// 使用String作为主键类型
let stringIdMapper = IdQueryMapper<String, Product>(
dataType: StringDataType(false, 'product_code'),
putter: { product, code => product.code = code }
)
实战应用示例
示例1:用户实体主键查询
// 定义用户实体
public class User {
public var id: Int64
public var name: String
public var email: String
public init() {}
}
// 创建主键映射器
let useridMapper = IdQueryMapper<Int64, User>(
dataType: Int64DataType(false, 'id'),
putter: { user, id => user.id = id }
)
// 在QueryMappers中使用
let userMappers = QueryMappers<User>(
mappers: [
useridMapper,
FieldQueryMapper<String, User>(
dataType: StringDataType(false, 'name'),
putter: { user, name => user.name = name }
),
FieldQueryMapper<String, User>(
dataType: StringDataType(false, 'email'),
putter: { user, email => user.email = email }
)
],
creator: { User() }
)
// 执行查询
let result = sqlExecutor.query("SELECT id, name, email FROM users WHERE id = ?", params: [userId])
let user = userMappers.one(result)
示例2:复合查询映射器配置
// 自动生成的查询映射器配置
public class UserQueryMappers {
public static prop queryMappers: QueryMappers<User> {
get() {
QueryMappers<User>(
mappers: [
IdQueryMapper<Int64, User>(
dataType: Int64DataType(false, 'id'),
putter: { user, id => user.id = id }
),
FieldQueryMapper<String, User>(
dataType: StringDataType(false, 'name'),
putter: { user, name => user.name = name }
),
FieldQueryMapper<String, User>(
dataType: StringDataType(false, 'email'),
putter: { user, email => user.email = email }
)
],
creator: { User() }
)
}
}
}
高级特性与最佳实践
1. 类型约束保障安全
IdQueryMapper要求主键类型实现Hashable & Equatable<ID>接口,这确保了:
- 主键值可以作为Map的键使用
- 支持相等性比较
- 适用于分组查询等高级场景
2. 空值安全处理
通过Option类型和getOrThrow方法,提供了完善的空值处理机制:
// 安全的主键获取
let userId: Int64 = idMapper.id(result) // 如果为空会抛出异常
// 安全的可选获取
if (let Some(userId) <- idMapper.get<Int64>(result)) {
// 处理有值的情况
}
3. 性能优化策略
- 列信息缓存: QueryResultWrap缓存列名到索引的映射,避免重复计算
- 结果数据缓存: 使用ArrayList缓存查询结果,减少数据库访问次数
- 类型转换优化: 内置数据类型系统避免反射开销
4. 错误处理机制
try {
let user = userMappers.one(result)
match user {
case Some(u) => processUser(u)
case None => log.warn("User not found")
}
} catch (e: TypeCastException) {
log.error("Type conversion error: ${e.message}")
} catch (e: Exception) {
log.error("Query failed: ${e.message}")
}
常见问题解决方案
Q1: 如何处理复合主键?
对于复合主键场景,可以使用GroupedQueryMapper结合多个IdQueryMapper:
let compositeMapper = GroupedQueryMapper<User>(
mappers: [
IdQueryMapper<Int64, User>(/* 第一部分主键 */),
IdQueryMapper<String, User>(/* 第二部分主键 */)
]
)
Q2: 自定义主键类型如何支持?
只要自定义类型实现Hashable和Equatable接口即可:
public class CustomId : Hashable, Equatable<CustomId> {
public let value: String
public func hash(into hasher: inout Hasher) {
hasher.combine(value)
}
public func equals(other: CustomId): Bool {
value == other.value
}
}
// 使用自定义主键类型
let customIdMapper = IdQueryMapper<CustomId, Entity>(/* ... */)
Q3: 性能调优建议
- 批量查询: 使用
list()方法代替多次one()调用 - 索引优化: 确保数据库表的主键索引正确建立
- 连接池: 合理配置数据库连接池参数
- 缓存策略: 对热点数据实施缓存机制
总结与展望
IdQueryMapper作为fountain ORM框架的核心组件,提供了强大而灵活的主键查询能力。通过类型安全的泛型设计、完善的错误处理机制和性能优化策略,它极大地简化了数据库主键操作。
读完本文你能得到:
- ✅ 掌握IdQueryMapper的核心原理和使用方法
- ✅ 学会处理各种类型的主键查询场景
- ✅ 了解性能优化和错误处理的最佳实践
- ✅ 能够解决实际开发中的主键查询问题
随着fountain框架的持续发展,IdQueryMapper将继续增强对新型数据库的支持、提供更丰富的查询优化特性,为仓颉语言开发者提供更强大的ORM解决方案。
下一步学习建议:
- 探索GroupedQueryMapper进行分组查询
- 学习NestQueryMapper处理嵌套对象映射
- 了解SqlExecutor的完整查询能力
如果本文对你有帮助,请点赞/收藏/关注三连支持! 下期我们将深入解析fountain的GroupedQueryMapper分组查询机制。
更多推荐
所有评论(0)