查询构建器
Use、Table、Raw、Select、Join、Group、分页、锁、流式读取和终结方法参考。
Oro 的查询入口只有三个:
db.Use[Product]()
db.Table("products")
db.Raw("select * from products where id = ?", id)
模型查询使用 Go 字段名;裸表和 Raw 使用数据库列名。
文档分工:
模型查询
product, err := db.Use[Product]().Where("Code", "P001").First(ctx)
常用链式方法:
| 方法 | 用途 |
|---|---|
Where / OrWhere |
字段条件或条件对象 |
WhereGroup / OrWhereGroup |
括号分组 |
WhereWhen |
条件成立时追加分组 |
WhereRaw |
原生条件片段 |
WhereColumn |
列与列比较 |
WhereIn / WhereExists |
子查询条件 |
Select |
选择字段、表达式、聚合 |
With |
预加载关系 |
For |
通过关系查询目标侧 |
As |
设置主表别名 |
Join / LeftJoin / RightJoin / FullJoin |
Join 查询 |
CrossJoin / JoinRaw |
特殊 Join |
OrderBy / OrderByDesc / OrderByRaw |
排序 |
GroupBy / Having / HavingRaw |
分组和聚合过滤 |
HavingColumn / HavingIn / HavingExists |
分组后的列比较和子查询过滤 |
Limit / Offset |
限制和偏移 |
LockForUpdate / LockForShare |
行锁 |
WithDeleted / OnlyDeleted |
软删除查询 |
Shard / AllShards |
分片查询 |
UsePrimary |
强制读主库 |
Cache / CacheKey / CacheTags |
查询缓存 |
Timeout |
查询级超时 |
SkipHooks / SkipEvents |
跳过模型 Hook 或全局事件 |
裸表查询
rows, err := db.Table("products").Where("price", ">=", 100).Get(ctx)
Table 返回 oro.Map。需要结构体时使用 MapTo[T]():
views, err := db.Table("products").
Select("id", "code", "price").
MapTo[ProductView]().
Get(ctx)
Table(...).MapTo[T]() 支持 First、Get、Stream、Chunk、Each、Paginate、Create、CreateManyResult 和 UpsertMany。聚合统计仍然调用底层 Table 查询的 Count、Exists、Sum、Avg、Min、Max。
Raw(...).MapTo[T]() 支持 First、Get 和 Stream;Raw 的执行型 SQL 使用 Raw(...).Exec(ctx)。
Raw 查询
rows, err := db.Raw("select * from "+db.TableName("products")+" where code = ?", code).Get(ctx)
Raw 支持:
| 方法 | 用途 |
|---|---|
First(ctx) |
返回一行 oro.Map 或 nil |
Get(ctx) |
返回 []oro.Map |
MapTo[T]() |
映射到结构体 |
Stream(ctx) |
流式读取 |
Exec(ctx) |
执行非查询 SQL |
Cache / CacheKey / CacheTags |
缓存 Raw 读结果 |
Timeout |
设置超时 |
Raw SQL 不会自动处理表前缀。需要表前缀时使用 db.TableName("products")。
Select
Select 可以混合字段名、别名表达式、聚合表达式、Raw 表达式和关系聚合表达式。
rows, err := db.Table("orders").
Select(
"status",
oro.Count("*").As("total"),
oro.Sum("amount").As("amount_sum"),
oro.Raw("max(created_at) as last_created_at"),
).
GroupBy("status").
Get(ctx)
模型查询里字段名使用 Go 字段名:
products, err := db.Use[Product]().Select("ID", "Code", "Price").Get(ctx)
聚合表达式支持 Count、Sum、Avg、Min、Max,都可以通过 .As(alias) 设置别名。字段别名用 oro.As(field, alias)。
聚合表达式也遵循入口字段规则:db.Use[Order]().Select(oro.Sum("Amount")) 使用 Go 字段名;db.Table("orders").Select(oro.Sum("amount")) 使用数据库列名。oro.Raw(...) 和 "o.amount" 这类已限定字段按 SQL 处理。
Group 和 Having
rows, err := db.Table("orders").
Select("status", oro.Count("*").As("total")).
GroupBy("status").
HavingRaw("count(*) > ?", 10).
Get(ctx)
可用方法:
| 方法 | 用途 |
|---|---|
GroupBy(fields...) |
分组字段 |
Having(field, value) |
field = value |
Having(field, op, value) |
分组后的字段条件 |
HavingColumn(left, args...) |
分组后的列比较 |
HavingIn(field, oro.Query(query)) |
HAVING field IN (subquery) |
HavingExists(oro.Query(query)) |
HAVING EXISTS (subquery) |
HavingRaw(sql, args...) |
原生 having 条件 |
Having 不接收回调。结构化 Having 的字段名仍遵循入口规则;如果要按聚合别名或聚合表达式过滤,使用 HavingRaw,或把聚合放到子查询后在外层 Where 过滤。
Join
Join 使用回调统一表达 ON 条件。查询过滤条件仍然写在外层 Where。
rows, err := db.Table("orders").As("o").
LeftJoin("users", func(j *oro.Join) {
j.As("u").OnColumn("u.id", "o.user_id")
}).
Where("o.status", "paid").
Get(ctx)
Join 条件方法:
| 方法 | 用途 |
|---|---|
As(alias) |
设置 join 表别名 |
OnColumn(left, right) |
列等值比较 |
OnColumn(left, op, right) |
列操作符比较 |
OrOnColumn(left, args...) |
OR 列比较 |
Where(field, args...) |
Join 条件值比较 |
OrWhere(field, args...) |
OR Join 条件值比较 |
WhereGroup(fn) |
Join 条件分组,追加为 AND (...) |
支持的 Join 类型:
| 方法 | SQL 语义 |
|---|---|
Join(source, fn) |
inner join |
LeftJoin(source, fn) |
left join |
RightJoin(source, fn) |
right join |
FullJoin(source, fn) |
full join,取决于驱动能力 |
CrossJoin(table) |
cross join |
JoinRaw(sql, args...) |
原生 join 片段 |
source 可以是表名,也可以是 oro.Query(...).As(alias) 子查询。
latestOrders := db.Table("orders").
Select("user_id", oro.Raw("max(id) as last_order_id")).
GroupBy("user_id")
rows, err := db.Table("users").As("u").
LeftJoin(oro.Query(latestOrders).As("lo"), func(j *oro.Join) {
j.OnColumn("lo.user_id", "u.id")
}).
Get(ctx)
Join 回调里可以写分组:
rows, err := db.Table("orders").As("o").
Join("users", func(j *oro.Join) {
j.As("u").
OnColumn("u.id", "o.user_id").
WhereGroup(func(g *oro.Join) {
g.Where("u.status", "active").
OrWhere("u.vip", true)
})
}).
Get(ctx)
当前 Join 只提供 WhereGroup,没有单独的 OrWhereGroup。需要 OR 条件时,在 group 内用 OrWhere 表达。
字段别名使用 oro.As(field, alias),主表别名使用查询的 As(alias),Join 表别名使用 j.As(alias):
rows, err := db.Table("orders").As("o").
Select(oro.As("o.status", "status"), oro.Count("*").As("total")).
Join("users", func(j *oro.Join) {
j.As("u").OnColumn("u.id", "o.user_id")
}).
GroupBy("o.status").
Get(ctx)
子查询
oro.Query(query) 把 Use / Table 查询作为子查询源。
paidOrders := db.Table("orders").Select("user_id").Where("status", "paid")
users, err := db.Table("users").
WhereIn("id", oro.Query(paidOrders)).
Get(ctx)
作为 From 或 Join 源时可以设置别名:
rows, err := db.From(oro.Query(paidOrders).As("po")).Get(ctx)
终结方法
| 方法 | 返回 |
|---|---|
First(ctx) |
一条或 nil |
Find(ctx, id) |
主键查询一条或 nil,模型查询可用 |
Get(ctx) |
切片 |
Count(ctx) |
int64 |
Exists(ctx) |
bool |
Sum(ctx, field) / Avg(ctx, field) |
oro.Decimal |
Min[T](ctx, field) / Max[T](ctx, field) |
oro.Null[T] |
Stream(ctx) |
流式迭代器 |
Chunk(ctx, size, fn) |
分块读取 |
Each(ctx, fn) |
逐行读取 |
Paginate(size) |
分页器 |
Create / CreateMany / CreateManyResult |
写入 |
Upsert / UpsertMany |
冲突写入 |
Update / Delete |
更新或删除 |
查询返回规则
- 单条查不到返回
nil, nil; - 多条查不到返回空切片;
Exists查不到返回false, nil;- 只有连接、SQL、扫描、约束、事务等问题才返回 error。