Golang Gorm 一对多 preload预加载

预加载示例  preload + find/take


 GORM允许使用 Preload通过多个SQL中来直接加载关系, 例如:

type User struct {
  gorm.Model
  Username string
  Orders   []Order
}

type Order struct {
  gorm.Model
  UserID uint
  Price  float64
}

// 查找 user 时预加载相关 Order
db.Preload("Orders").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4);



// 预加载Orders、Profile、Role多个关联属性  ps: 预加载字段,必须是User的属性
db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)

// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many
// SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one
// SELECT * FROM roles WHERE id IN (4,5,6); // belongs to
	var u []User
	db.Debug().Preload("Articles").Find(&u)
	fmt.Println(u)

[1.486ms] [rows:7] SELECT * FROM `article` WHERE `article`.`user_id` IN (1,2,3)

[2.644ms] [rows:3] SELECT * FROM `user`
[{1 lucas [{1 golang 1} {2 k8s 1}]} {2 yanzi [{3 golang 2} {4 k8s 2}]} {3 test [{5 redis 3} {6 cherry 3} {7 marry 3}]}]
	var u User
	db.Debug().Where("name = ?", "lucas").Find(&u)
	fmt.Printf("%#v\n", u)

	db.Debug().Preload("Articles").Find(&u)
	fmt.Printf("%#v\n", u)

	var a Article
	db.Debug().Take(&a, 8)
	fmt.Printf("%#v\n", a)

	db.Debug().Preload("User").Find(&a)
	fmt.Printf("%#v\n", a)

[1.306ms] [rows:4] SELECT * FROM `article` WHERE `article`.`user_id` = 1

[3.628ms] [rows:1] SELECT * FROM `user` WHERE `user`.`id` = 1
main.User{ID:1, Name:"lucas", Articles:[]main.Article{main.Article{ID:1, Title:"k8s", UserID:1, User:main.User{ID:0, Name:"", Arti
cles:[]main.Article(nil)}}, main.Article{ID:2, Title:"golang", UserID:1, User:main.User{ID:0, Name:"", Articles:[]main.Article(nil
)}}, main.Article{ID:9, Title:"c", UserID:1, User:main.User{ID:0, Name:"", Articles:[]main.Article(nil)}}, main.Article{ID:10, Tit
le:"ruby", UserID:1, User:main.User{ID:0, Name:"", Articles:[]main.Article(nil)}}}}


[1.667ms] [rows:1] SELECT * FROM `article` WHERE `article`.`id` = 8 LIMIT 1
main.Article{ID:8, Title:"c++", UserID:3, User:main.User{ID:0, Name:"", Articles:[]main.Article(nil)}}


[1.124ms] [rows:1] SELECT * FROM `user` WHERE `user`.`id` = 3


[3.090ms] [rows:1] SELECT * FROM `article` WHERE `article`.`id` = 8
main.Article{ID:8, Title:"c++", UserID:3, User:main.User{ID:3, Name:"jerry", Articles:[]main.Article(nil)}}

preload的原理


其实很简单,你要preload user表的数据,gorm就提前把这张表全部取出来,然后再执行FirstFind这样的方法去查询主数据,最后把两种数据通过外键关联一一对应起来。

其实preload也就是做了两次查询。

	var u User
	db.Debug().Preload("Articles").Take(&u, "name = ?", "test")
	fmt.Println(u)


[2.007ms] [rows:3] SELECT * FROM `article` WHERE `article`.`user_id` = 3

[3.056ms] [rows:1] SELECT * FROM `user` WHERE name = 'test' LIMIT 1
{3 test [{5 redis 3} {6 cherry 3} {7 marry 3}]}

带条件预加载  只想展示某些


 

	var u User
	db.Debug().Where("name = ?", "lucas").Find(&u)

	db.Debug().Preload("Articles", "id = ?", 2).Find(&u)
	fmt.Println(u)

{1 lucas [{2 golang 1 {0  []}}]}

嵌套预加载


	var a Article
	db.Debug().Take(&a, 8)
	db.Debug().Preload("User.Articles").Find(&a)
	fmt.Printf("%#v\n", a)

[4.840ms] [rows:1] SELECT * FROM `article` WHERE `article`.`id` = 8
main.Article{ID:8, Title:"c++", UserID:3, User:main.User{ID:3, Name:"jerry", Articles:[]main.Article{main.Article{ID:8, Title:"c++", UserID:3, User:m
ain.User{ID:0, Name:"", Articles:[]main.Article(nil)}}}}}

级联删除


	var u User
	
	db.Debug().Where("name = ?", "lisa").Find(&u)
	db.Debug().Select("Articles").Delete(&u)

[0.748ms] [rows:1] SELECT * FROM `user` WHERE name = 'lisa'
[2.106ms] [rows:1] DELETE FROM `article` WHERE `article`.`user_id` = 4
[6.887ms] [rows:1] DELETE FROM `user` WHERE `user`.`id` = 4

清除外键关系   Association + Delete、Clean


 有了preload,那么user就可以通过.点出来。

	db.Debug().Preload("Articles").Take(&u, 1
	)
	fmt.Println(u)


[4.167ms] [rows:1] SELECT * FROM `user` WHERE `user`.`id` = 1 LIMIT 1
{1 lucas [{1 k8s 1 {0  []}} {2 golang 1 {0  []}} {9 c 1 {0  []}} {10 ruby 1 {0  []}}]}
	var u User
	db.Take(&u, 2)
	db.Model(&u).Association("Articles").Find(&u.Articles)
	db.Debug().Model(&u).Association("Articles").Delete(&u.Articles)

[4.128ms] [rows:2] UPDATE `article` SET `user_id`=NULL WHERE `article`.`user_id` = 2 AND `article`.`id` IN (3,7)

mysql> select * from user;
+----+-------+
| id | name  |
+----+-------+
|  2 | yanzi |
|  3 | lucas |
|  4 | yanzi |
+----+-------+
3 rows in set (0.00 sec)

mysql> select * from article;
+----+--------+---------+
| id | title  | user_id |
+----+--------+---------+
|  1 | golang |    NULL |
|  2 | k8s    |    NULL |
|  3 | c#     |       2 |
|  4 | golang |       3 |
|  5 | k8s    |       3 |
|  6 | c#     |       4 |
|  7 | oracle |       2 |
+----+--------+---------+
7 rows in set (0.00 sec)

#修改之后

mysql> select * from user;
+----+-------+
| id | name  |
+----+-------+
|  2 | yanzi |
|  3 | lucas |
|  4 | yanzi |
+----+-------+

mysql> select * from article;
+----+--------+---------+
| id | title  | user_id |
+----+--------+---------+
|  1 | golang |    NULL |
|  2 | k8s    |    NULL |
|  3 | c#     |    NULL |
|  4 | golang |       3 |
|  5 | k8s    |       3 |
|  6 | c#     |       4 |
|  7 | oracle |    NULL |
+----+--------+---------+

  清空关联关系示例:先清空关联关系,再删除

	var u User
	db.Take(&u, 1)
	db.Debug().Model(&u).Association("Articles").Clear()

[11.177ms] [rows:2] UPDATE `article` SET `user_id`=NULL WHERE `article`.`user_id` = 1



mysql> select * from user;
+----+-------+
| id | name  |
+----+-------+
|  1 | lucas |
|  2 | yanzi |
|  3 | lucas |
|  4 | yanzi |
+----+-------+

mysql> select * from article;
+----+--------+---------+
| id | title  | user_id |
+----+--------+---------+
|  1 | golang |    NULL |
|  2 | k8s    |    NULL |
|  3 | c#     |       2 |
|  4 | golang |       3 |
|  5 | k8s    |       3 |
|  6 | c#     |       4 |
|  7 | oracle |       2 |
+----+--------+---------+


db.Debug().Delete(&u)
[9.960ms] [rows:1] DELETE FROM `user` WHERE `user`.`id` = 1


mysql> select * from user;
+----+-------+
| id | name  |
+----+-------+
|  2 | yanzi |
|  3 | lucas |
|  4 | yanzi |
+----+-------+

mysql> select * from article;
+----+--------+---------+
| id | title  | user_id |
+----+--------+---------+
|  1 | golang |    NULL |
|  2 | k8s    |    NULL |
|  3 | c#     |       2 |
|  4 | golang |       3 |
|  5 | k8s    |       3 |
|  6 | c#     |       4 |
|  7 | oracle |       2 |
+----+--------+---------+
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用Golang GORM进行MySQL递归查询单表的示例代码: ```go package main import ( "fmt" "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) type Category struct { ID int Name string ParentID int Children []Category `gorm:"foreignkey:ParentID"` } func main() { db, err := gorm.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database?charset=utf8mb4&parseTime=True&loc=Local") if err != nil { panic(err) } defer db.Close() var categories []Category db.Where("parent_id = ?", 0).Preload("Children").Find(&categories) for _, category := range categories { fmt.Println(category.Name) for _, child := range category.Children { fmt.Println(" ", child.Name) } } } ``` 在这个示例中,我们定义了一个Category结构体,其中包含ID、Name、ParentID和Children字段。Children字段是一个Category类型的切片,用于存储子类别。在结构体中,我们使用了GORM的foreignkey标记来指定ParentID字段是外键,Children字段是通过ParentID字段与Category表关联的。 在main函数中,我们首先使用GORM的Open函数打开MySQL数据库连接。然后,我们定义了一个categories切片,用于存储查询结果。我们使用GORM的Where函数指定ParentID为0,即查询所有顶级类别。然后,我们使用GORMPreload函数加载Children字段,以便在查询结果中包含子类别。最后,我们使用GORM的Find函数执行查询,并将结果存储在categories切片中。 最后,我们遍历categories切片,并打印每个类别及其子类别的名称。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值