完美解决 gorm表初始化 外键报错、define a valid foreign key for ...

在使用GORM的创建foreignKey关系的时,不管是按照官方文档给的例子写,还是说加上`gorm:"foreignKey:ID;references:UserId;"` 这样的,都是一样报错:define a valid foreign key for ... ,网上大部分给出的解决方案是gorm后面直接用"-"。如下图

 
type User struct {gorm.ModelUserName    string    `json:"user_name" gorm:"comment:用户名"`Blogs       []Blog`    json:"blogs" gorm:"-"`
}type Blog struct {gorm.ModelTitle       string    `json:"title      "gorm:"comment:标题"`Content     string    `json:"Content    "gorm:"comment:正文"`UserId      uint      `json:"user_id    "gorm:"comment:作者ID"`
}

这样确实可以绕过这个错误,但是官方提供的预加载(Preload)等高级方法用不了,

完美解决办法:

我们可以将需要创建外键的表拆开来写,还是上面的例子,我们可以这样写

type BaseUser struct {gorm.ModelUserName    string    `json:"user_name" gorm:"comment:用户名"`
}// 设置表名
func (BaseUser) TableName() string {return "user"
}type User struct {BaseUser Blogs     []Blog`   json:"blogs" gorm:"foreignKey:Id;references:UserId;"`
}// 设置表名
func (User) TableName() string {return "user"
}type Blog struct {gorm.ModelTitle       string    `json:"title      "gorm:"comment:标题"`Content     string    `json:"Content    "gorm:"comment:正文"`UserId      uint      `json:"user_id    "gorm:"comment:作者ID"`
}

这样我们在执行db.Debug().Migrator().AutoMigrate()创建表的时候创建 BaseUser,但是在代码中查询的时候使用User;如下图,可以查询出所有的用户,并且每个用户的所有blog也会一次性查询出来,避免了写原生SQL查询或者要多次循环才能查询出每个用户的所有blog

func  FindUser(db *gorm.DB) error {var (err errorusers = []User{})err = db.Debug().Model(&User{}).Preload("Blogs").  //这里要注意Find(&users).Errorif err != nil {log.Errorf("db error: %s", err)return err}return err
}

同样如果需要在查询Blog列表的时候想要直接查出作者的信息,就需要在Blog表中加上user,如下图:

type BaseUser struct {gorm.ModelUserName    string    `json:"user_name" gorm:"comment:用户名"`
}// 设置表名
func (BaseUser) TableName() string {return "user"
}type User struct {BaseUser Blogs     []BaseBlog  `json:"blogs" gorm:"foreignKey:Id;references:UserId"`
}// 设置表名
func (User) TableName() string {return "user"
}type BaseBlog struct {gorm.ModelTitle       string    `json:"title      "gorm:"comment:标题"`Content     string    `json:"Content    "gorm:"comment:正文"`UserId      uint      `json:"user_id    "gorm:"comment:作者ID"`
}// 设置表名
func (BaseBlog) TableName() string {return "blog"
}type Blog struct {BaseBlog User User  `json:"user" gorm:"foreignKey:UserId;references:Id;"`
}
// 设置表名
func (Blog) TableName() string {return "blog"
}

查询blog列表的时候也是同样操作,就可以同时查询出User的字段

func  FindUser(db *gorm.DB) error {var (err errorBlogs = []Blog{})err = db.Debug().Model(&Blog{}).Preload("User").Find(&Blogs ).Errorif err != nil {log.Errorf("db error: %s", err)return err}return err
}

  当然还有其他很多高级的用法,比如在查询用户列表时候除了可以同时查询出该用户的所有blog,还可以对blog进行统计,需要稍微改一下User表结构,并使用GORM钩子,如下

type BaseUser struct {gorm.ModelUserName    string    `json:"user_name" gorm:"comment:用户名"`
}// 设置表名
func (BaseUser) TableName() string {return "user"
}type User struct {BaseUser Blogs         []BaseBlog  `json:"blogs" gorm:"foreignKey:Id;references:UserId"`BlogsCount    int         `json:"blogs_count" gorm:"-"` //这样的只是为了返回给前端,没必要创建数据库字段,所以增加了gorm:"-"
}// 设置表名
func (User) TableName() string {return "user"
}// 利用GORM钩子对每个用户的blog进行统计
func (e *User) AfterFind(_ *gorm.DB) error {e.BlogsCount = len(e.Blogs)return nil
}type BaseBlog struct {gorm.ModelTitle       string    `json:"title      "gorm:"comment:标题"`Content     string    `json:"Content    "gorm:"comment:正文"`UserId      uint      `json:"user_id    "gorm:"comment:作者ID"`
}// 设置表名
func (BaseBlog) TableName() string {return "blog"
}type Blog struct {BaseBlog User User  `json:"user" gorm:"foreignKey:UserId;references:Id;"`
}
// 设置表名
func (Blog) TableName() string {return "blog"
}

这样可以完美解决建表的错误,还能使用Preload等高级方法,并且我们知道如果数据库真的创建外键之后有很多数据库约束,维护起来很麻烦,这样做数据库中还不会创建外键,非常完美的解决多个问题。更多GORM高级用法可以参考官方文档GORM Guides | GORM - The fantastic ORM library for Golang, aims to be developer friendly.


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部