📦GORMv1.25.6

🏆 关联模式的CRUD

🍅 预加载查询

前面已经提到过了预加载查询可以将关联的数据也一起查询出来这里就不做演示,重点介绍其他预加载方法

🌟 嵌套预加载

⭐️ 嵌套预加载,可以将预加载中的数据中的数据一层一层给显示出来,我查询这个任务,需要将这个任务的用户查询出来并且显示出它的其他任务就可以使用嵌套预加载

这里我直接使用如下模型进行接下来的操作,注意这里需要结合第四篇的知识点,它是一个多对多模型,并且重写了外键,可以一个人完成多个任务,也可以多个人完成一个任务,

// User 创建结构体对应表
type User struct {
	gorm.Model
	Name     string `gorm:"unique;not null;index:,unique"`
	Password string 
	Tasks    []Task `gorm:"many2many:user_doc;foreignKey: Name;joinForeignKey:UserName;References: Title;JoinReferences: TaskName;"` // 多对多关系,使用many2many:user_doc 表示中间表
}

// Task 用户任务表
type Task struct {
	gorm.Model
	Title string `gorm:"comment: 文章Title;index:,unique"`
	Users []User `gorm:"many2many:user_doc;foreignKey: Title;joinForeignKey:TaskName;References: Name;JoinReferences:UserName;"` // 多对多关系,使用many2many:user_doc 表示中间表
}

// UserDoc 自定义连接表
type UserDoc struct {
	UserName  string `gorm:"primaryKey;"`
	TaskName  string `gorm:"primaryKey"`
	CreatedAt time.Time
	DeletedAt gorm.DeletedAt
}

用嵌套查询,之前先创建数据

	u1 := &User{
		Name:     "tanc",
		Password: "1234567",
		Tasks: []Task{
			{Title: "JavaWeb大作业"},
			{Title: "安卓大作业"},
			{Title: "web大作业"},
		},
	}

	t1 := &Task{
		Title: "嵌入式实训",
		Users: []User{
			*u1,
			{Name: "zs", Password: "123456"},
		},
	}
	db.Create(u1)
	db.Create(t1)

创建完成之后使用嵌入查询,可以看到将User表的任务都列出来了,还列出了当前用户

var task Task
db.Model(&Task{}).Preload("Users.Tasks").Find(&task, 1)
fmt.Println(task)


//输出结果
{{1 2024-07-03 15:41:54.763 +0800 CST 2024-07-03 15:41:54.763 +0800 CST {0001-01
-01 00:00:00 +0000 UTC false}} JavaWeb大作业 [{{1 2024-07-03 15:41:54.737 +0800 
CST 2024-07-03 15:41:54.737 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} tan
c 1234567 [{{1 2024-07-03 15:41:54.763 +0800 CST 2024-07-03 15:41:54.763 +0800 C
ST {0001-01-01 00:00:00 +0000 UTC false}} JavaWeb大作业 []} {{2 2024-07-03 15:41
:54.763 +0800 CST 2024-07-03 15:41:54.763 +0800 CST {0001-01-01 00:00:00 +0000 U
TC false}} 安卓大作业 []} {{3 2024-07-03 15:41:54.763 +0800 CST 2024-07-03 15:41
:54.763 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} web大作业 []} {{4 2024-
07-03 15:41:54.765 +0800 CST 2024-07-03 15:41:54.765 +0800 CST {0001-01-01 00:00
:00 +0000 UTC false}} 嵌入式实训 []}]}]}

🌟 带条件预加载

//查询用户,并且预加载任务且只显示id为1的
var user User
db.Model(&User{}).Preload("Tasks", "id = ?", 1).Take(&user, 1)
fmt.Println(user)

//输出
{{1 2024-07-03 15:41:54.737 +0800 CST 2024-07-03 15:41:54.737 +0800 CST {0001-01
-01 00:00:00 +0000 UTC false}} tanc 1234567 [{{1 2024-07-03 15:41:54.763 +0800 C
ST 2024-07-03 15:41:54.763 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} Java
Web大作业 []}]}


🌟 自定义预加载

var user User
db.Model(&User{}).Preload("Tasks", func(db *gorm.DB) *gorm.DB {
    return db.Where("title = ?", "安卓大作业")
}).Take(&user, 1)
fmt.Println(user)


//输出
{{1 2024-07-03 15:41:54.737 +0800 CST 2024-07-03 15:41:54.737 +0800 CST {0001-01
-01 00:00:00 +0000 UTC false}} tanc 1234567 [{{2 2024-07-03 15:41:54.763 +0800 C
ST 2024-07-03 15:41:54.763 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} 安卓
大作业 []}]}

🍅 关联模式的CRUD

🌟 Select/Omit 关联字段

⭐️在 GORM 中,当创建或更新记录时,您可以使用 SelectOmit方法来专门包含或排除关联模型的某些字段。

  1. 使用 Select,您可以指定在保存主模型时应包含关联模型的哪些字段。这对于有选择地保存关联的部分尤其有用。
  2. 相反,Omit允许您排除关联模型的某些字段而不进行保存。当您想阻止关联的特定部分被持久化时,这会很有用。
用户 := 用户{
  名称:             “jinzhu”,
  BillingAddress:地址{地址1:“帐单地址 - 地址 1”,地址2:“addr2” },
  ShippingAddress:地址{地址1:“送货地址 - 地址 1”,地址2:“addr2” },
}

// 创建用户及其 BillingAddress、ShippingAddress,仅包括 BillingAddress 的指定字段
db.Select( "BillingAddress.Address1" , "BillingAddress.Address2" ).Create(&user) 
// SQL:仅使用“Address1”和“Address2”字段创建用户和 BillingAddress

// 创建用户及其 BillingAddress、ShippingAddress,不包括 BillingAddress 的特定字段
db.Omit( "BillingAddress.Address2" , "BillingAddress.CreatedAt" ).Create(&user) 
// SQL:创建用户和 BillingAddress,省略 'Address2' 和 'CreatedAt' 字段

🌟 关联模式

1️⃣ 查询关联

检索有或无附加条件的相关记录。

//Many to Many创建关系
u1 := &User{
    Name:     "tanc",
    Password: "1234567",
    Tasks: []Task{
        {Title: "JavaWeb大作业"},
        {Title: "安卓大作业"},
        {Title: "web大作业"},
    },
}

var tasks []Task
//需要指定一个实列对象,而不是一个空实列
db.Model(&u1).Association("Tasks").Find(&tasks)
for _, t := range tasks {
    fmt.Println(t)
}

//输出,这里并没有显示用户只是查看此用户由多少个任务
{{1 2024-07-03 16:31:41.791 +0800 CST 2024-07-03 16:31:41.791 +0800 CST {0001-01
-01 00:00:00 +0000 UTC false}} JavaWeb大作业 []}
{{2 2024-07-03 16:31:41.791 +0800 CST 2024-07-03 16:31:41.791 +0800 CST {0001-01
-01 00:00:00 +0000 UTC false}} 安卓大作业 []}
{{3 2024-07-03 16:31:41.791 +0800 CST 2024-07-03 16:31:41.791 +0800 CST {0001-01
-01 00:00:00 +0000 UTC false}} web大作业 []}


2️⃣ 追加关联

添加新的关联为 many to many, has many,或者替换当前的关联为 has one, belong to

//追加关联
var tasks []Task
db.Preload("Tasks").First(&u1)
err = db.Debug().Model(u1).Association("Tasks").Append([]Task{{Title: "暑假冲冲冲"}})
if err != nil {
    println("追加关联失败", err.Error())
}

db.Model(u1).Association("Tasks").Find(&tasks)
for _, t := range tasks {
    fmt.Println(t)
}


//输出
{{1 2024-07-03 16:51:27.473 +0800 CST 2024-07-03 16:51:27.473 +0800 CST {0001-01
-01 00:00:00 +0000 UTC false}} JavaWeb大作业 []}
{{2 2024-07-03 16:51:27.473 +0800 CST 2024-07-03 16:51:27.473 +0800 CST {0001-01
-01 00:00:00 +0000 UTC false}} 安卓大作业 []}
{{3 2024-07-03 16:51:27.473 +0800 CST 2024-07-03 16:51:27.473 +0800 CST {0001-01
-01 00:00:00 +0000 UTC false}} web大作业 []}
{{4 2024-07-03 16:51:52.967 +0800 CST 2024-07-03 16:51:52.967 +0800 CST {0001-01
-01 00:00:00 +0000 UTC false}} 暑假冲冲冲 []}

3️⃣ 替换关联

用新的关联取代当前的关联。

//替换关联
var tasks []Task
db.Preload("Tasks").First(&u1)
err = db.Debug().Model(u1).Association("Tasks").Replace([]Task{{Title: "暑假冲冲冲"}})
if err != nil {
    println("追加关联失败", err.Error())
}

db.Model(u1).Association("Tasks").Find(&tasks)
for _, t := range tasks {
    fmt.Println(t)
}


//输出,这里就只有一条任务了
{{4 2024-07-03 16:51:52.967 +0800 CST 2024-07-03 16:51:52.967 +0800 CST {0001-01
-01 00:00:00 +0000 UTC false}} 暑假冲冲冲 []}

4️⃣ 删除关联

删除源和参数之间的关系,仅删除引用

//删除关联
var tasks []Task
db.Preload("Tasks").First(&u1)
err = db.Debug().Model(u1).Association("Tasks").Delete([]Task{{Title: "暑假冲冲冲"}})
if err != nil {
    println("追加关联失败", err.Error())
}

//删除之后这里输出空
db.Model(u1).Association("Tasks").Find(&tasks)
for _, t := range tasks {
    fmt.Println(t)
}

5️⃣ 清空关联

和删除差不多,只不过它是直接全部清除

//清除关联
var tasks []Task
db.Model(u1).Association("Tasks").Find(&tasks)
fmt.Println("清除前:")
for _, t := range tasks {
    fmt.Println(t)
}

db.Preload("Tasks").First(&u1)
err = db.Model(u1).Association("Tasks").Clear()
if err != nil {
    println("追加关联失败", err.Error())
}

//删除之后这里输出空
db.Model(u1).Association("Tasks").Find(&tasks)
fmt.Println("清除后:")
for _, t := range tasks {
    fmt.Println(t)
}


//输出结果
清除前:
{{1 2024-07-03 16:51:27.473 +0800 CST 2024-07-03 16:51:27.473 +0800 CST {0001-01
-01 00:00:00 +0000 UTC false}} JavaWeb大作业 []}
{{2 2024-07-03 16:51:27.473 +0800 CST 2024-07-03 16:51:27.473 +0800 CST {0001-01
-01 00:00:00 +0000 UTC false}} 安卓大作业 []}
{{3 2024-07-03 16:51:27.473 +0800 CST 2024-07-03 16:51:27.473 +0800 CST {0001-01
-01 00:00:00 +0000 UTC false}} web大作业 []}


清除后:

6️⃣ 获取关联数量

//获取关联数量
count := db.Model(&u1).Association("Tasks").Count()
fmt.Println("当前关联数量为: ", count)


//输出:
当前关联数量为:  4

7️⃣ (硬)删除/清空记录关联

将关联从数据库中直接删除

db.Model(&u1).Association("Tasks").Unscoped().Delete(&Task{Title: "JavaWeb大作业"})
db.Model(&u1).Association("Tasks").Unscoped().Clear()