package model
import "gorm.io/gorm"
type User struct {
gorm.Model
CreditCards []*CreditCard `gorm:"foreignKey:UserId"`
type CreditCard struct {
gorm.Model
Number string `gorm:"number;type:varchar(30);not null"`
UserId uint
package main
import (
"ShopBefore/gorm/model"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"time"
func main() {
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
"root", "root", "192.168.193.128", 3306, "test")
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: time.Second,
LogLevel: logger.Info,
IgnoreRecordNotFoundError: true,
Colorful: true,
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
if err != nil {
panic(err)
var users []model.User
user := model.User{
CreditCards: []*model.CreditCard{
Number: "123",
Number: "456",
Number: "789",
user1 := model.User{
CreditCards: []*model.CreditCard{
Number: "321",
Number: "654",
Number: "987",
users = append(users,user)
users = append(users,user1)
db.Save(&users)
INSERT INTO `credit_cards` (`created_at`,`updated_at`,`deleted_at`,`number`,`user_id`) VALUES ('2022-06-20 22:40:07.591','2022-06-20 22:40:07.591',NULL,'123',1),('2022-06-20 22:40:07.591','2022-06-20 22:40:07.591',NULL,'456',1),('2022-06-20 22:40:07.591','2022-06-20 22:40:07.591',NULL,'789',1),('2022-06-20 22:40:07.591','2022-06-20 22:40:07.591',NULL,'321',2),('2022-06-20 22:40:07.591','2022-06-20 22:40:07.591',NULL,'654',2),('2022-06-20 22:40:07.591','2022-06-20 22:40:07.591',NULL,'987',2) ON DUPLICATE KEY UPDATE `user_id`=VALUES(`user_id`)
INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`) VALUES ('2022-06-20 22:40:07.532','2022-06-20 22:40:07.532',NULL),('2022-06-20 22:40:07.532','2022-06-20 22:40:07.532',NULL) ON DUPLICATE KEY UPDATE `updated_at`='2022-06-20 22:40:07.532',`deleted_at`=VALUES(`deleted_at`)
package main
import (
"ShopBefore/gorm/model"
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"time"
func main() {
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
"root", "root", "192.168.193.128", 3306, "test")
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: time.Second,
LogLevel: logger.Info,
IgnoreRecordNotFoundError: true,
Colorful: true,
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
if err != nil {
panic(err)
var user model.User
db.Preload("CreditCards").Find(&user,2)
marshal, _ := json.Marshal(user)
fmt.Println(string(marshal))
SELECT * FROM `credit_cards` WHERE `credit_cards`.`user_id` = 2 AND `credit_cards`.`deleted_at` IS NULL
SELECT * FROM `users` WHERE `users`.`id` = 2 AND `users`.`deleted_at` IS NULL
"ID": 2,
"CreatedAt": "2022-06-20T22:40:07.532+08:00",
"UpdatedAt": "2022-06-20T22:40:07.532+08:00",
"DeletedAt": null,
"CreditCards": [
"ID": 4,
"CreatedAt": "2022-06-20T22:40:07.591+08:00",
"UpdatedAt": "2022-06-20T22:40:07.591+08:00",
"DeletedAt": null,
"Number": "321",
"UserId": 2
"ID": 5,
"CreatedAt": "2022-06-20T22:40:07.591+08:00",
"UpdatedAt": "2022-06-20T22:40:07.591+08:00",
"DeletedAt": null,
"Number": "654",
"UserId": 2
"ID": 6,
"CreatedAt": "2022-06-20T22:40:07.591+08:00",
"UpdatedAt": "2022-06-20T22:40:07.591+08:00",
"DeletedAt": null,
"Number": "987",
"UserId": 2
官方文档看起来很容易误导,让开发以为一对多的关系就必须要存在外键,但是我们再真实的开发环境下,大多是不会用到数据库中的物理外键的,仅仅只是做一个逻辑关联就够了.官方文档这里说的必须存在外键是我们再model里面必须要指明外键,而不是数据库中一定要有这个外键,
注意: 这种情况我们就不能使用db.AutoMigrate() 来自动创建表了,因为我们再代码中指明外键,如果再使用
db.AutoMigrate() 来创建表,那么gorm是一定会帮我们做一个物理外键的
gorm一对多官方文档设置外键的缺点代码modelmain新增日志:查询日志:结果:最后官方文档看起来很容易误导,让开发以为一对多的关系就必须要存在外键,但是我们再真实的开发环境下,大多是不会用到数据库中的物理外键的,仅仅只是做一个逻辑关联就够了.官方文档这里说的必须存在外键是我们再model里面必须要指明外键,而不是数据库中一定要有这个外键,注意: 这种情况我们就不能使用db.AutoMigrate() 来自动创建表了,因为我们再代码中指明外键,如果再使用db.AutoMi
"gorm.io/driver/mysql"
DB , err := gorm . Open ( mysql . Open ( "db1_dsn" ), & gorm. Config {})
DB . Use ( dbresolver . Register (dbresolver. Config {
// use `db2` as sources, `db3`, `db4` as replicas
Sources : []gorm. Dialect
belongs to 关联建立一个和另一个模型的一对一连接,使得模型声明每个实例都「属于」另一个模型的一个实例 。例如,如果你的应用包含了用户和用户资料, 并且每一个用户资料只分配给一个用户
为了定义从属关系, 外键是必须存在的, 默认的外键使用所有者类型名称加上其主键。像上面的例子,为了声明一个模型属于 User,它的外键应该为 UserID。GORM 提供了一个定制外键的方法,例如:
关联外键
对于从属关系, GORM 通常使用所有者的主键作为外键值,在上面的例子中,就是 User 的 ID。当你
gorm 表初始化报错、外键报错:define a valid foreign key for relations or implement the Valuer/Scanner interface
type DtProject struct {
gorm.Model
Name string `json:"name" form:"name" gorm:"column:name;comment:;type:varchar(191);"`
type DtProjectWorkerRel struct {
gorm.Model
ProjectId uint `json:"projectId" gorm:"comment:项目id;unique_inde
会与另一个模型建立了一对一的连接。 这种模型的每一个实例都“属于”另一个模型的一个实例。例如,您的应用包含 user 和 company,并且每个 user 能且只能被分配给一个 company。下面的类型就表示这种关系。 注意,在 对象中,有一个和 一样的 。 默认情况下, 被隐含地用来在 和 之间创建一个外键关系, 因此必须包含在 结构体中才能填充 内部结构体。
请参阅 预加载 以了解内部结构的详细信息。要定义一个 belongs to 关系,数据库的表中必须存在外键。默认情况下,外键的名
在 设置外键的时候不是只将字段和要关联的外键的结构体对应上就可以了, 还需要写一个关联的字段id 如:
type Blog struct {
ID uint `gorm:"primary_key"`
Title string `gorm:"not null;size:256"`
Content string `gorm:"type:text;not null"`
ShowContent string `gorm:"not null"`
LookNum int `gorm:"defau