gorm代码生成工具如何生成两个模型的双向关系?

比如两个表,user和post:
user hasMany post
post belongTo user

gen工具里面关系配置函数gen.FieldRelate,第三个table参数是个对象。
要生成双向关系变量会互相依赖,只能生成一方的。
怎么解?

阅读 921
avatarAI BotBETA
// 解决方案:分文件定义模型关系避免循环依赖

// 文件 user_gen.go
func initUserModel(g *gen.Generator) {
    user := g.GenerateModel("users",
        gen.FieldRelate(gen.HasMany, "Posts", 
            gen.GeneratedModel("posts"), // 直接使用生成后的模型名称
            &field.RelateConfig{
                GORMTag: "foreignKey:UserID;references:ID",
            }),
    )
    g.ApplyBasic(user)
}

// 文件 post_gen.go
func initPostModel(g *gen.Generator) {
    post := g.GenerateModel("posts",
        gen.FieldRelate(gen.BelongsTo, "User",
            gen.GeneratedModel("users"),
            &field.RelateConfig{
                GORMTag: "foreignKey:UserID;references:ID",
            }),
    )
    g.ApplyBasic(post)
}

// 关键点说明:
1. 分文件定义模型,避免Go的循环依赖
2. gen.GeneratedModel("table_name") 代替直接模型引用
3. 通过g.ApplyBasic分步应用模型定义
4. 确保外键关系配置一致:
   - User表使用hasMany时配置foreignKey指向Post表的UserID
   - Post表使用belongsTo时foreignKey保持相同UserID
5. 生成顺序无关,工具会自动处理依赖

// 生成命令:
// 在main.go中按顺序调用初始化函数
2 个回答
✓ 已被采纳
package main

import (
    "gorm.io/driver/mysql"
    "gorm.io/gen"
    "gorm.io/gorm"
)

func main() {
    db, _ := gorm.Open(mysql.Open("user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"))
    
    g := gen.NewGenerator(gen.Config{
        OutPath: "./dal/query",
        Mode: gen.WithDefaultQuery,
    })
    
    g.UseDB(db)
    
    user := g.GenerateModelAs("users", "User")
    post := g.GenerateModelAs("posts", "Post")
    
    // 先应用基本模型
    g.ApplyBasic(user, post)
    
    // 然后添加关系
    userWithPosts := g.GenerateModel("users", 
        gen.FieldRelate(field.HasMany, "Posts", post, &field.RelateConfig{
            RelateField: "UserID",
        }),
    )
    
    postWithUser := g.GenerateModel("posts", 
        gen.FieldRelate(field.BelongsTo, "User", user, &field.RelateConfig{
            RelateField: "UserID",
        }),
    )
    
    // 应用带关系的模型
    g.ApplyBasic(userWithPosts, postWithUser)
    
    // 执行生成
    g.Execute()
}

解决方案

  1. 使用字符串类型名称代替结构体引用
    gen.FieldRelate配置中,将关联模型类型用字符串表示(如"Post"、"User"),避免直接引用未生成的结构体。
  2. 正确配置外键约束
    RelateConfig中显式指定foreignKey,确保关联关系的GORM标签正确生成。
// 生成User模型时配置HasMany关系
user := g.GenerateModel("users",
    gen.FieldRelate(model.HasMany, "Posts", "Post", 
        &field.RelateConfig{
            GORMTag: field.GormTag{"foreignKey": []string{"UserID"}},
        }),
)

// 生成Post模型时配置BelongsTo关系
post := g.GenerateModel("posts",
    gen.FieldRelate(model.BelongsTo, "User", "User", 
        &field.RelateConfig{
            GORMTag: field.GormTag{"foreignKey": []string{"UserID"}},
        }),
)

// 将模型加入生成器
g.ApplyBasic(user, post)

关键点说明

  • 字符串类型名称:用"Post""User"替代结构体类型,解决编译时的循环依赖。
  • 外键一致性:两侧均通过foreignKey:UserID指明外键,确保GORM能正确识别关联。
  • 生成顺序无关:由于使用字符串引用,无需担心模型生成的先后顺序。

生成结果示例

// User模型
type User struct {
    ID    int64
    Posts []Post `gorm:"foreignKey:UserID"` // HasMany
}

// Post模型
type Post struct {
    ID     int64
    UserID int64
    User   User `gorm:"foreignKey:UserID"` // BelongsTo
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题