V2

关联查询

  1. // user
  2. type TbUser struct {
  3. dbUtils.FieldsModel
  4. ID uint `gorm:"primarykey"`
  5. CompanyID int
  6. Name string
  7. Tag string
  8. Age int
  9. }
  10. type TbCompany struct {
  11. dbUtils.FieldsModel
  12. Address string
  13. Name string
  14. }
  15. type TbCard struct {
  16. ID uint `gorm:"primarykey"`
  17. UserID uint
  18. Number int
  19. }
  20. type TbLanguage struct {
  21. ID uint `gorm:"primarykey"`
  22. Name string
  23. }
  24. // 当使用 GORM 的 AutoMigrate 为 User 创建表时,GORM 会自动创建连接表。这里只是展示
  25. type TbUserLanguage struct {
  26. LanguageId uint
  27. UserId uint
  28. }
  29. type FieldsModel struct {
  30. ID uint `gorm:"primarykey"`
  31. CreatedAt int64 `gorm:"autoCreateTime:milli;type:bigint(13);unsigned;comment:创建时间" json:"created_at"`
  32. UpdatedAt int64 `gorm:"autoUpdateTime:milli;type:bigint(13);unsigned;comment:修改时间" json:"updated_at"`
  33. DeletedAt soft_delete.DeletedAt `gorm:"type:bigint(13);unsigned;comment:删除时间" json:"deleted_at"`
  34. }

Belongs To 属于

  1. // 一个用户属于一个公司
  2. // user.company_id -> company.id
  3. func TestPageParamBelongsTo(t *testing.T) {
  4. type User struct {
  5. TbUser
  6. Company TbCompany
  7. }
  8. res := &[]User{}
  9. err := DB.Preload(clause.Associations).Find(res).Error
  10. fmt.Println(err)
  11. }

Has One 一对一

  1. // 一个用户有一张唱片
  2. // user.id -> card.user_id
  3. func TestPageParamHasOne(t *testing.T) {
  4. type User struct {
  5. TbUser
  6. Card TbCard
  7. }
  8. res := &[]User{}
  9. err := DB.PreloadAll().Find(res).Error
  10. fmt.Println(err)
  11. }

Has Many 一对多

  1. // 一个用户有多张唱片
  2. // user.id -> []card.user_id
  3. func TestPageParamHasMany(t *testing.T) {
  4. type User struct {
  5. TbUser
  6. Card []TbCard
  7. }
  8. res := &[]User{}
  9. err := DB.PreloadAll().Find(res).Error
  10. fmt.Println(err)
  11. }

Many To Many 多对多

  1. // `user_languages` 是连接表
  2. func TestPageParamManyToMany(t *testing.T) {
  3. type Language struct {
  4. TbLanguage
  5. Users []*TbUser `gorm:"many2many:user_languages;"`
  6. }
  7. type User struct {
  8. TbUser
  9. Languages []*Language `gorm:"many2many:user_languages;"`
  10. }
  11. // 正向: 一个人会多种语言 user <- []language
  12. // user.id -> user_languages.user_id,[]language_id -> language.id
  13. func() {
  14. res := &[]User{}
  15. err := DB.PreloadAll().Find(res).Error
  16. fmt.Println(err)
  17. }()
  18. // 反向: 一群人会一种语言 language <- []user
  19. // language.id -> user_languages.language_id,[]user_id -> user.id
  20. func() {
  21. res := &[]Language{}
  22. err := DB.PreloadAll().Find(res).Error
  23. fmt.Println(err)
  24. }()
  25. }

Preload 预加载

加载层级

例:Orders.OrderItems.Product

层级递归查询

例 公司部门下属,家庭父子关系。

  1. // 一个iss:https://github.com/go-gorm/gorm/issues/4027
  2. // 官方递归:https://gorm.io/docs/has_many.html#Self-Referential-Has-Many
  3. type Person struct {
  4. ID string `gorm:"type:uuid;primaryKey;default:gen_random_uuid()" form:"id" json:"id"`
  5. Name string `json:"name"`
  6. ParentID *string `json:"parent_id" gorm:"type:uuid"`
  7. Children []Person `gorm:"foreignKey:ParentID" json:"children"`
  8. }
  9. func TestChildren(t *testing.T) {
  10. // 注意:ParentID 是 `*string` 类型,查询没有问题。
  11. // 关联添加的时候必须给指针类型(非指针插入会报错),使用指针会关联插入。
  12. data := Person{
  13. Name: "a1",
  14. Children: []Person{
  15. {
  16. Name: "a2",
  17. Children: []Person{
  18. {
  19. Name: "a3",
  20. },
  21. },
  22. },
  23. },
  24. }
  25. DB.Create(&data)
  26. var result Person
  27. // 第一个 Preload 加载其他的关联
  28. // 第二个 Preload 加载 Children 的关系
  29. DB.Preload(clause.Associations).Preload("Children." + clause.Associations).Find(&result)
  30. }

运行结果
image.png

  1. // INSERT INTO "person" (name, parent_id) VALUES ("a1", "");
  2. // INSERT INTO "person" (name, parent_id) VALUES ("a2", "da185c9c-1717-4720-9fd3-4cc26fc2659d");
  3. // INSERT INTO "person" (name, parent_id) VALUES ("a3", "e1cea70b-6eb4-4b83-8500-7a87a65c5fd1");
  4. // 这个是倒叙的
  5. // SELECT * FROM "person" WHERE "person"."parent_id" = 'e1cea70b-6eb4-4b83-8500-7a87a65c5fd1'
  6. // SELECT * FROM "person" WHERE "person"."parent_id" = 'da185c9c-1717-4720-9fd3-4cc26fc2659d'
  7. // SELECT * FROM "person"

相关社区

  • go-gorm/datatypes - 支持 json、jsonMap、date类型。 ``go type Available struct { Use booljson:”use”Reason stringjson:”reason”` }

// Scan scan value into Jsonb, implements sql.Scanner interface func (a *Available) Scan(value interface{}) error { json return nil }

func (a Available) Value() (driver.Value, error) { return fmt.Sprintf((%t,"%s"), a.Use, a.Reason), nil }

  1. - [pq](https://github.com/lib/pq) - `BoolArray` `ByteaArray` `Float32Array` `Int32Array` `StringArray` `GenericArray 自定义类型数组` 等等数组类型。帮助我们使用 postgreSQL 的数据类型。
  2. ```go
  3. // 使用 GenericArray 完成 []AvailableArray 结构
  4. type AvailableArray []Available
  5. func (a *AvailableArray) Scan(src interface{}) error {
  6. return pq.GenericArray{A: a}.Scan(src)
  7. }
  8. func (a AvailableArray) Value() (driver.Value, error) {
  9. if a == nil {
  10. return "{}", nil
  11. }
  12. return pq.GenericArray{A: a}.Value()
  13. }
  14. func (a AvailableArray) MarshalJSON() ([]byte, error) {
  15. res := make([]Available, 0)
  16. if a != nil {
  17. res = a
  18. }
  19. return json.Marshal(res)
  20. }

V1 已过时

文档:官方中文文档tag 介绍
注意:以下是一些需要特别注意的:

debug:
  1. // 启用Logger,显示详细日志
  2. db.LogMode(true)
  3. // 禁用日志记录器,不显示任何日志
  4. db.LogMode(false)
  5. // 调试单个操作,显示此操作的详细日志
  6. db.Debug().Where("name = ?", "jinzhu").First(&User{})

事务:
  1. // 开始事务
  2. tx := db.Begin()
  3. // 在事务中做一些数据库操作(从这里必须使用'tx',而不是'db')
  4. tx.Create(...)
  5. // ...
  6. // 发生错误时回滚事务
  7. tx.Rollback()
  8. // 或提交事务
  9. tx.Commit()