仓储 Repository
为每个 @Entity 类,ACE ORM 在编译期自动生成一个对应的 <Entity>Repository 类并注册为 Bean。无需手动继承任何基类——直接用 @Inject 注入即可使用。
注入 Repository
cangjie
package demo.controller
import ace_framework.*
import ace_orm.*
import demo.model.*
@Controller["/tasks"]
public class TaskController {
@Inject
var repo: TaskRepository
@Get["/"]
func list(): Array<Task> {
repo.findAll()
}
}基础 CRUD 方法
所有 Repository 均实现 Repository<T> 接口,提供以下方法:
| 方法签名 | 说明 |
|---|---|
insert(t: T): T | 插入记录,返回带自增 id 的实体 |
findById(id: DbValue): Option<T> | 按主键查询,未找到返回 None |
findAll(): Array<T> | 查询全部记录 |
findAll(where: String, params: Array<DbValue>): Array<T> | 带条件查询 |
update(t: T): Bool | 按主键更新,返回是否成功 |
delete(id: DbValue): Bool | 按主键删除,返回是否成功 |
count(): Int64 | 返回总记录数 |
query(sql: String, params: Array<DbValue>): Array<T> | 执行自定义 SQL |
插入与查询
cangjie
// 插入
let task = Task()
task.title = "实现登录接口"
task.priority = 2
task.owner = "alice"
let saved = repo.insert(task)
// saved.id 已被填充为数据库自增 id
// 按主键查询
match (repo.findById(DbInt(saved.id))) {
case Some(t) => println(t.title)
case None => println("未找到")
}
// 查询全部
let all = repo.findAll()条件查询
findAll 支持传入 WHERE 子句和绑定参数,防止 SQL 注入:
cangjie
// 查询 priority > 1 的任务
let urgent = repo.findAll(
where: "priority > ?",
params: [DbInt(1)]
)
// 多条件组合
let mine = repo.findAll(
where: "owner = ? AND priority >= ?",
params: [DbString("alice"), DbInt(2)]
)DbValue 类型速查
| 仓颉类型 | 包装为 |
|---|---|
Int64 | DbInt(v) |
String | DbString(v) |
Float64 | DbFloat(v) |
Bool | DbBool(v) |
None | DbNull |
手动 SQL 查询
当内置方法无法满足需求时,使用 query 执行原生 SQL:
cangjie
// 聚合查询:按 owner 统计任务数
let rows = repo.query(
"SELECT owner, COUNT(*) as cnt FROM tasks GROUP BY owner",
params: []
)
// 复杂 JOIN(关联表需手动映射)
let highPriority = repo.query(
"SELECT t.* FROM tasks t WHERE t.priority = (SELECT MAX(priority) FROM tasks)",
params: []
)query 返回值
query 返回 Array<T>,ACE ORM 按列名自动映射到实体字段。若 SELECT 列与字段名不一致,需使用 AS 别名对齐字段名。
更新与删除
cangjie
// 先查后改
match (repo.findById(DbInt(1))) {
case Some(t) =>
t.priority = 3
repo.update(t)
case None => ()
}
// 删除
let ok = repo.delete(DbInt(1))
if (!ok) {
println("记录不存在或已删除")
}统计
cangjie
let total = repo.count()
println("共 ${total} 条任务")事务支持
需要跨多个操作保证原子性时,在 Service 方法上使用 @Transactional。详见 @Transactional 文档。
cangjie
package demo.service
import ace_framework.*
import ace_orm.*
import demo.model.*
@Service
public class TaskService {
@Inject
var repo: TaskRepository
@Transactional
public func createAndLink(title: String, parentId: Int64): Task {
let task = Task()
task.title = title
let saved = repo.insert(task)
// 若此处抛出异常,insert 会自动回滚
linkToParent(saved.id, parentId)
saved
}
}并发注意
Repository Bean 默认为单例作用域,其内部持有数据库连接池而非单一连接,并发安全。但若直接操作底层连接对象,请确保在同一事务内使用同一连接。
禁止在 @Entity 类中持有可变共享状态
实体类是纯数据载体,不要在字段中缓存业务对象或注入其他 Bean——Repository 查询每次返回新的实体实例,跨请求共享实体对象会导致数据竞争。