关于gorm多表关联关系查询使用案例

9,796 阅读4分钟

一、简单的对gorm的封装使用

  • 1、下载依赖包

    go get -u gorm.io/gorm
    gorm.io/driver/mysql
    
  • 2、在utils的文件夹下封装一个数据库的连接方法

    package utils
    
    import (
        "fmt"
        _ "github.com/go-sql-driver/mysql"
        "gorm.io/driver/mysql"
        "gorm.io/gorm"
        "gorm.io/gorm/logger"
        "gorm.io/gorm/schema"
    )
    
    var GormDb *gorm.DB
    
    func init() {
        var err error
        sqlStr := "root:123456@tcp(localhost:3306)/beego?charset=utf8mb4&parseTime=true&loc=Local"
        // 关于配置可以参考 https://gorm.io/zh_CN/docs/gorm_config.html
        GormDb, err = gorm.Open(mysql.Open(sqlStr), &gorm.Config{
            Logger: logger.Default.LogMode(logger.Info),
            //DisableForeignKeyConstraintWhenMigrating: true, // 禁止创建外键
            NamingStrategy: schema.NamingStrategy{ // 给创建表时候使用的
                SingularTable: true,
                // 全部的表名前面加前缀
                //TablePrefix: "mall_",
            },
        })
        if err != nil {
            fmt.Println("数据库连接错误", err)
            return
        }
    }
    
  • 3、封装一个将map转换为字符串的方法

    import "encoding/json"
    
    func MapToJson(data interface{}) string {
        byteStr, _ := json.Marshal(data)
        return string(byteStr)
    }
    

二、一对一的关联关系

  • 1、参考文档,建议大家先阅读文档

  • 2、这里就不使用官网案例,直接使用用户和身份证号码的两个表来举例,一个用户只有一个身份证号码,一个身份证号码也只能属于一个用户

  • 3、创建数据模型并且自动映射生成到数据库中

    type UserEntity struct {
        Id   int    `json:"id" gorm:"type:int(11);autoIncrement;primaryKey;column:id;"` // 主键id
        Name string `json:"name" gorm:"type:varchar(30);not null;"`                     //姓名
        Age  int    `json:"age" gorm:"type:int(11);default:0;"`
    }
    
    type IdCardEntity struct {
        Id int    `json:"id" gorm:"type:int(11);autoIncrement;primaryKey;column:id;"` // 主键id
        No string `json:"no" gorm:"type:varchar(20);not null;"`                       // 身份证号码
        //外键关联到用户表
        User   UserEntity `json:"user"`
        UserId int        `json:"user_id"`
    }
    
    func (UserEntity) TableName() string {
        return "user"
    }
    func (IdCardEntity) TableName() string {
        return "id_card"
    }
    
    func init() {
        utils.GormDb.AutoMigrate(&UserEntity{}, &IdCardEntity{})
    }
    
  • 4、映射生成的数据表结构如下

    -- 用户表的数据结构
    +-------+-------------+------+-----+---------+-------+
    | Field | Type        | Null | Key | Default | Extra |
    +-------+-------------+------+-----+---------+-------+
    | id    | int(11)     | NO   | PRI | <null>  |       |
    | name  | varchar(30) | NO   |     | <null>  |       |
    | age   | int(11)     | YES  |     | 0       |       |
    +-------+-------------+------+-----+---------+-------+
    -- 身份证表
    +---------+-------------+------+-----+---------+-------+
    | Field   | Type        | Null | Key | Default | Extra |
    +---------+-------------+------+-----+---------+-------+
    | id      | int(11)     | NO   | PRI | <null>  |       |
    | no      | varchar(20) | NO   |     | <null>  |       |
    | user_id | int(11)     | YES  | MUL | <null>  |       |
    +---------+-------------+------+-----+---------+-------+
    
  • 5、使用Joins的方式连表的方式查询用户及身份证号码出来

    var userListEntity []map[string]interface{}
    utils.GormDb.Model(&UserEntity{}).Select("user.id", "user.name", "user.age", "id_card.no").
    Joins("left join id_card on user.id = id_card.user_id").Scan(&userListEntity)
    
    fmt.Println(tools.MapToJson(userListEntity))
    
    [{"age":10,"id":1,"name":"张三","no":"110"}]
    
  • 6、使用Preload反向在身份证表中去查询用户信息

    var idCardListEntity []IdCardEntity
    utils.GormDb.Preload("User").Find(&idCardListEntity)
    
    fmt.Println(tools.MapToJson(idCardListEntity))
    
    [{"id":1,"no":"110","user":{"id":1,"name":"张三","age":10},"user_id":1}]
    

三、一对多的关联关系

  • 1、官网地址,自行观看官网内容

  • 2、这里我们举例班级和学生的关联关系,一个班级有多个学生,学生只能属于一个班级的案例

  • 3、创建数据模型

    type ClassEntity struct {
     Id          int              `json:"id" gorm:"type:int(11);autoIncrement;primaryKey;column:id;`
     Name        string           `json:"name"`
      // 一个班级中有多个学生foreignKey表示外键关联的字段
     StudentList []*StudentEntity `json:"student_list" gorm:"foreignKey:ClassId"`
    }
    
    type StudentEntity struct {
     Id   int    `json:"id" gorm:"type:int(11);autoIncrement;primaryKey;column:id;`
     Name string `json:"name"`
      // 外键关联到班级表的数据模型
     ClassId int `json:"class_id"`
    }
    
    func (StudentEntity) TableName() string {
     return "student"
    }
    
    func (ClassEntity) TableName() string {
     return "class"
    }
    
    func init() {
     utils.GormDb.AutoMigrate(&ClassEntity{}, &StudentEntity{})
    }
    
  • 4、自己手动插入数据

  • 5、查询班级列表并且查询全部的学生出来

    var classList []ClassEntity
    utils.GormDb.Preload("StudentList").Find(&classList)
    
    fmt.Println(tools.MapToJson(classList))
    
    [{"id":1,"name":"班级一","student_list":[{"id":1,"name":"学生一","class_id":1},{"id":2,"name":"学生二","class_id":1}]}]
    
  • 6、查询学生想顺带查询出班级

    • 学生表上添加一个字段(直接添加就可以)

      type StudentEntity struct {
         Id   int    `json:"id"`
         Name string `json:"name"`
         + Class   ClassEntity `json:"class"` // 需要反向查询的时候加上
         ClassId int `json:"class_id"`
      }
      
    • 查询数据

      var studentList []StudentEntity
      utils.GormDb.Joins("Class").Find(&studentList)
      fmt.Println(tools.MapToJson(studentList))
      
      [{"id":1,"name":"学生一","class":{"id":1,"name":"班级一","student_list":null},"class_id":1},{"id":2,"name":"学生二","class":{"id":1,"name":"班级一","student_list":null},"class_id":1}]
      

四、多对多的关联关系

  • 1、官网地址

  • 2、我们这里举例账号和角色的关联关系,一个账号可以有多个角色,一个角色也可以给多个账号的关系

  • 3、定义数据模型

    type AccountEntity struct {
     Id    int           `json:"id"`
     Name  string        `json:"name"`
     Roles []*RoleEntity `json:"roles" gorm:"many2many:account_role;foreignKey:Id;joinForeignKey:accountId;joinReferences:roleId;"`
    }
    
    type RoleEntity struct {
     Id    int    `json:"id"`
     Title string `json:"title"`
     Accounts []*AccountEntity `json:"accounts" gorm:"many2many:account_role;foreignKey:Id;joinForeignKey:roleId;joinReferences:accountId"`
    }
    
    func (AccountEntity) TableName() string {
     return "account"
    }
    
    func (RoleEntity) TableName() string {
     return "role"
    }
    
    func init() {
     utils.GormDb.AutoMigrate(&AccountEntity{}, &RoleEntity{})
    }
    
  • 4、上面几个用到的字段解析说明,官网介绍地址

    • many2many:user_profiles 定义中间表名为:user_profiles
    • foreignKey:Id 使用当前表的id作为外键
    • joinForeignKey:accountId 当前数据模型外键关联到中间件表的字段名叫accountId
    • joinReferences:roleId 反向引用字段,如果是账号表就要写中间表的roleId
  • 5、手动添加数据库

  • 6、查找账号列表顺便查询出角色信息

    var accountList []AccountEntity
    utils.GormDb.Preload("Roles").Find(&accountList)
    fmt.Println(tools.MapToJson(accountList))
    
    [
     {
        "id":1,
        "name":"账号一",
        "roles":[
           {"id":1,"title":"角色一","accounts":null},
           {"id":2,"title":"角色二","accounts":null}
        ]
     },
     {
        "id":2,
        "name":"账号二",
        "roles":[
           {"id":1,"title":"角色一","accounts":null}
        ]
     }
    ]
    
  • 7、根据角色查询到账号信息

    var roleList []RoleEntity
    utils.GormDb.Preload("Accounts").Find(&roleList)
    fmt.Println(tools.MapToJson(roleList))
    
    [
     {
        "id":1,
        "title":"角色一",
        "accounts":[
           {"id":1,"name":"账号一","roles":null},
           {"id":2,"name":"账号二","roles":null}
        ]
     },
     {
        "id":2,
        "title":"角色二",
        "accounts":[
           {"id":1,"name":"账号一","roles":null}
        ]
     }
    ]
    

五、数据模型

上面仅仅是演示使用关于数据模型的完善需要自己参考官网,链接地址