Files
easygoadmin-wiki/EasyGoAdmin_GoFrame_EleVue/zh/guide/model.md
T
2026-10-20 21:19:44 +08:00

110 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 3.3 DAO 数据层
:::tip 概述
DAO 四件(dao/{m}.go、dao/internal/{m}.go、entity、do)由 `gf gen dao` 或代码生成器产出,无需手写。但 `dao.{X}.Ctx(ctx)` 是全系统**唯一查询入口**(架构红线),理解它的两行自定义模板逻辑至关重要。
:::
## 四件产出与职责
| 文件 | 产出方式 | 职责 |
|------|---------|------|
| `internal/dao/{m}.go` | 自定义模板 hack/tpl/dao_index.tpl | 挂全局钩子 + Ctx 覆写(红线执行点) |
| `internal/dao/internal/{m}.go` | gf gen dao | 内部实现(列常量/表名/基础查询),勿手改 |
| `internal/model/entity/{m}.go` | gf gen dao | 实体结构体(对齐表列) |
| `internal/model/do/{m}.go` | gf gen dao | 数据对象 DO(Insert/Update 入参形态) |
## 真实代码(internal/dao/example.go,摘自项目)
```go
// =================================================================================
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
// 自定义模板:hack/tpl/dao_index.tpl
// - 构造时挂载全局模型钩子(审计字段 / 软删除改写;主键交数据库自增)
// - Ctx 覆写注入软删除与租户隔离条件(架构红线执行点)
// =================================================================================
package dao
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"easygoadmin/internal/dao/internal"
"easygoadmin/internal/model/hooks"
)
// exampleDao is the data access object for the table goframe_example.
// You can define custom methods on it to extend its functionality as needed.
type exampleDao struct {
*internal.ExampleDao
}
var (
// Example is a globally accessible object for table goframe_example operations.
Example = exampleDao{
internal.NewExampleDao(func(m *gdb.Model) *gdb.Model {
// 全局钩子:Insert 补齐审计字段/租户ID(主键自增);Update 盖章;Delete 改写为软删除
return m.Hook(hooks.Handler())
}),
}
)
// Ctx 覆写:在 SQL 构建之前注入架构红线条件 ——
// 所有表追加 del_flag=0;租户级表对租户上下文追加 tenant_id IN (0, 当前租户)。
// 业务代码必须经由本方法访问模型,禁止绕过 dao 直连 DB。
func (d *exampleDao) Ctx(ctx context.Context) *gdb.Model {
return hooks.ApplyCtx(ctx, d.ExampleDao.Ctx(ctx), "goframe_example")
}
// Add your custom methods and functionality below.
```
## Ctx 覆写做了什么(hooks.ApplyCtx)
```text
dao.Example.Ctx(ctx)
│
├─ 所有表: WHERE del_flag = 0
└─ 租户级表且非平台上下文:WHERE tenant_id IN (0, 当前租户)
(租户用户看自己 + 平台共享行;超管 ctx tenant_id=0 不加过滤,全量可见)
```
## 全局钩子行为(hooks.Handler)
| 钩子 | 行为 |
|------|------|
| Insert | 主键交数据库自增(不填 id);补 del_flag=0、create_time、create_user(ctx 用户名,回退真实姓名);租户级表自动携带 tenant_id(租户用户零值→填自身;超管未指定→`tenant.defaultId`;显式 0 可建平台共享行) |
| Update | 自动盖章 update_time / update_user(仅 map 数据生效) |
| Delete | 物理删除一律改写为 `UPDATE del_flag=1`(软删) |
## 生成方式
```sh
# 方式一:表结构变更后刷新已实现模块的 dao
gf gen dao -c hack/config.yaml
# 方式二:新模块随生成器一次性产出(dao 四件与 gf gen dao 同构,生成后统一 gofmt)
go run ./cmd/generator -tables "goframe_example|案例演示表"
```
::: warning 三条红线
1. **禁止绕过 dao 直连 `g.DB()`**——软删/租户/审计全部失效。
2. **禁止手写 del_flag/tenant_id 条件**——`Ctx` 已自动注入,手写必错(漏平台行/漏软删行)。
3. **禁止手改 dao/internal/**——重新生成即被覆盖;自定义方法写在 `dao/{m}.go` 尾部。
:::
## 事务中的 dao
`WithTrans(ctx, fn)` 包裹的事务上下文内,`dao.{X}.Ctx(ctx)` 自动走事务连接:
```go
// internal/logic/base.go 的事务包裹(摘自项目)
// WithTrans 事务包裹(错误自动回滚)
func WithTrans(ctx context.Context, fn func(ctx context.Context) error) error {
// g.DB().Begin → fn(gdb.WithTX(ctx, tx)) → 出错 Rollback,否则 Commit
}
```
纪律:事务内禁止 HTTP/文件 IO;bcrypt 等 CPU 密集操作在事务外预计算(典型:租户开户、用户新增)。