98 lines
2.8 KiB
Markdown
98 lines
2.8 KiB
Markdown
# Ent Edges 使用说明(game 模块)
|
||
|
||
本文说明 `app/game/rpc/internal/models/schema` 下 Edges 的定义方式、生成方式,以及在业务代码中如何使用。
|
||
|
||
## 1. 当前 game 模块关系设计
|
||
|
||
基于 `desc/sql/game` 的表结构,当前主要关系:
|
||
|
||
- `players` 1:N `player_services`
|
||
- `player_services.player_id -> players.id`
|
||
- `shops` 1:N `shop_players`
|
||
- `shop_players.shop_id -> shops.id`
|
||
- `players` 1:N `shop_players`(逻辑关联)
|
||
- `shop_players.player_id -> players.id`
|
||
- `shops` 1:N `shop_invitations`
|
||
- `shop_invitations.shop_id -> shops.id`
|
||
- `players` 1:N `shop_invitations`(收到邀请)
|
||
- `shop_invitations.player_id -> players.id`
|
||
- `players` 1:N `shop_invitations`(发起邀请)
|
||
- `shop_invitations.invited_by -> players.id`
|
||
|
||
## 2. Edge 定义规则
|
||
|
||
### 2.1 在子表(持有外键字段)上定义 `edge.From(...).Field(...)`
|
||
|
||
示例(`player_services`):
|
||
|
||
- `edge.From("player", Players.Type).Ref("services").Field("player_id").Required().Unique()`
|
||
|
||
含义:
|
||
|
||
- 当前实体(`player_services`)通过 `player_id` 指向一个 `players`
|
||
- `Unique()` 表示每条 `player_services` 记录只对应一个 player(典型 N:1 子侧定义)
|
||
|
||
### 2.2 在父表定义反向 `edge.To(...)`
|
||
|
||
示例(`players`):
|
||
|
||
- `edge.To("services", PlayerServices.Type)`
|
||
|
||
含义:
|
||
|
||
- 一个 player 可以有多条 service(1:N)
|
||
|
||
## 3. 代码生成
|
||
|
||
在项目根目录执行:
|
||
|
||
```bash
|
||
go run entgo.io/ent/cmd/ent generate ./app/game/rpc/internal/models/schema
|
||
```
|
||
|
||
如果你后续为 schema 增加了注解或字段,重复执行同一命令即可刷新生成代码。
|
||
|
||
## 4. 业务查询示例
|
||
|
||
> 以下为典型写法,具体包路径以你项目实际生成结果为准。
|
||
|
||
### 4.1 查询某个玩家及其所有服务
|
||
|
||
```go
|
||
player, err := client.Players.
|
||
Query().
|
||
Where(players.ID(playerID)).
|
||
WithServices().
|
||
Only(ctx)
|
||
```
|
||
|
||
### 4.2 查询某个店铺及其成员关系记录
|
||
|
||
```go
|
||
shop, err := client.Shops.
|
||
Query().
|
||
Where(shops.ID(shopID)).
|
||
WithMemberships().
|
||
Only(ctx)
|
||
```
|
||
|
||
### 4.3 查询某玩家收到的邀请
|
||
|
||
```go
|
||
invitations, err := client.Players.
|
||
QueryReceivedInvitations(player).
|
||
All(ctx)
|
||
```
|
||
|
||
## 5. 常见坑
|
||
|
||
- `edge.From(...).Field(...)` 的字段名必须是当前 schema 里真实存在的字段。
|
||
- `Ref("...")` 名称要和对端 `edge.To("...")` 保持一致。
|
||
- 同一实体指向同一目标实体的多条边(例如邀请的 `player` 和 `inviter`)必须使用不同 edge 名称,避免代码生成冲突。
|
||
- 如果 SQL 没有声明外键但你定义了带 `Field(...)` 的 edge,迁移时可能会生成外键约束;若不想生成,请保持和 SQL 一致或在迁移层显式控制。
|
||
|
||
## 6. 当前文件位置
|
||
|
||
- Schema 目录:`app/game/rpc/internal/models/schema`
|
||
- SQL 来源:`desc/sql/game`
|