gorm 对象关系使用

1,542 阅读2分钟

目标

看了gorm文档,但是对多对多等关系有一些疑惑,官方也没有提供对象关系实现的代码,所以有了这篇文章.这篇文章解决以下问题:

  1. 代码实现并掌握使用"关联"使用方法
  2. 理解Belong to,has one,has many,many to many的含义和区别

没有对gorm其他部分做深入的探讨

过程

以下实现步骤都为"建模","迁移","数据对象写入","查询"四部分

Belongs To

文档

实现:

package main

import (
	"fmt"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

// `User` 属于 `Company`,`CompanyID` 是外键
type User struct {
	gorm.Model
	Name      string
	CompanyID int
	Company   Company
}

type Company struct {
	ID    int
	Name  string
	Users []User
}

func main() {

	db, err := gorm.Open(sqlite.Open("belongTo.db"), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}
	db.AutoMigrate(&User{})

	user := User{
		Name: "Tom",
		Company: Company{
			Name: "my Com",
		},
	}
	//db.Create(&user)
	// BEGIN TRANSACTION;
	// INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1"), ("Shipping Address - Address 1") ON DUPLICATE KEY DO NOTHING;
	// INSERT INTO "users" (name,billing_address_id,shipping_address_id) VALUES ("jinzhu", 1, 2);
	// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu@example.com"), (111, "jinzhu-2@example.com") ON DUPLICATE KEY DO NOTHING;
	// INSERT INTO "languages" ("name") VALUES ('ZH'), ('EN') ON DUPLICATE KEY DO NOTHING;
	// INSERT INTO "user_languages" ("user_id","language_id") VALUES (111, 1), (111, 2) ON DUPLICATE KEY DO NOTHING;
	// COMMIT;

	db.Save(&user)
	var getUser User
	rs := db.Preload("Company").Last(&getUser)
	fmt.Println(rs)

	//反向实现has many

	//company := Company{
	//	Name: "has many",
	//	Users: []User{
	//		{
	//			Name: "zhangsan",
	//		},
	//		{
	//			Name: "lisi",
	//		},
	//	},
	//}
	//db.Save(&company)
	var getCompany Company
	rs = db.Preload("Users").Last(&getCompany)
	fmt.Println(rs)
	fmt.Println(getCompany)
}

Has one

文档

实现:

package main

import (
	"encoding/json"
	"fmt"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

// User 有一张 CreditCard,CreditCardID 是外键
type User struct {
	gorm.Model
	CreditCard CreditCard
}

type CreditCard struct {
	gorm.Model
	Number string
	UserID uint
}

func main() {
	db, err := gorm.Open(sqlite.Open("hasOne.db"), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}
	db.AutoMigrate(&User{})
	db.AutoMigrate(&CreditCard{})

	user := User{
		CreditCard: CreditCard{
			Number: "10076",
		},
	}
	db.Create(&user)

	var getUser User
	rs := db.Preload("CreditCard").Last(&getUser)
	fmt.Println(rs)
	byt, _ := json.Marshal(getUser)
	fmt.Println(string(byt))

	//var getUser2 User
	var card CreditCard
	db.Model(&getUser).Association("CreditCard").Find(&card)
	fmt.Println()
}

Has Many

文档

package main

import (
	"encoding/json"
	"fmt"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

// User 有多张 CreditCard,UserID 是外键
type User struct {
	gorm.Model
	CreditCards []CreditCard
}

type CreditCard struct {
	gorm.Model
	Number string
	UserID uint
}

func main() {
	db, err := gorm.Open(sqlite.Open("hasMany.db"), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}
	db.AutoMigrate(&User{})
	db.AutoMigrate(&CreditCard{})

	user := User{
		CreditCards: []CreditCard{
			{
				Number: "10000",
			},
			{
				Number: "10001",
			},
		},
	}
	db.Create(&user)
	var getUser User
	rs := db.Preload("CreditCards").Last(&getUser)
	fmt.Println(rs)
	byt, _ := json.Marshal(getUser)
	fmt.Println(string(byt))
}

Many To Many

文档

package main

import (
	"encoding/json"
	"fmt"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

// User 拥有并属于多种 language,`user_languages` 是连接表
type User struct {
	gorm.Model
	Languages []Language `gorm:"many2many:user_languages;"`
}

type Language struct {
	gorm.Model
	Name  string
	Users []*User `gorm:"many2many:user_languages;"`
}

func main() {
	db, err := gorm.Open(sqlite.Open("manyToMany.db"), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}
	db.AutoMigrate(&User{})
	db.AutoMigrate(&Language{})

	user1 := User{
		Languages: []Language{
			{
				Name: "chinese",
			},
			{
				Name: "jpn",
			},
		},
	}
	user2 := User{
		Languages: []Language{
			{
				Name: "chinese",
			},
			{
				Name: "jpn",
			},
		},
	}
	db.Create(&user1)
	db.Create(&user2)

	var getUser User
	rs := db.Preload("Languages").Last(&getUser)
	fmt.Println(rs)
	byt, _ := json.Marshal(getUser)
	fmt.Println(string(byt))

	var getLanguage Language
	rs = db.Preload("Users").Last(&getLanguage)
	fmt.Println(rs)
	byt, _ = json.Marshal(getLanguage)
	fmt.Println(string(byt))

}

总结:

belong to 是和 has one和has many 的反向实现,实际使用根据需要拉取关联对象,在belong to部分也做了反向实现

many to many 是 has many的相互关系,可以通过关联表来实现

参考:

下面文章里搜到了比较好的总结,粘贴如下:

belongs_to  # 一对多,与 has_many,has_one 套用        
has_one      # 一对一          
has_many   # 一对多的另外一方            
has_and_belongs_to_many # 多对多

belongs_to,has_one,has_many,has_and_belongs_to_many