Salmon的全栈知识 Salmon的全栈知识
首页
  • JavaSE
  • JavaWeb
  • Spring生态
  • JUC
  • JVM
  • Netty
  • Java各版本特性
  • 23种设计模式
  • Maven
  • Java常用框架
  • Dubbo
  • OpenFeign
  • Nacos
  • Zookeeper
  • Sentinel
  • Seata
  • Gateway
  • Go基础
  • Gin
  • SQL数据库

    • MySQL
    • Oracle
  • NoSQL数据库

    • Redis
    • MongoDB
    • ElasticSearch
  • 消息中间件

    • RabbitMQ
    • RocketMQ
    • Kafka
    • ActiveMQ
    • MQTT
    • NATS
  • 网关中间件

    • Nginx
  • Linux
  • Docker
  • Git
  • K8s
  • Solidity
  • Java
  • 计算机网络
  • 操作系统
GitHub (opens new window)
首页
  • JavaSE
  • JavaWeb
  • Spring生态
  • JUC
  • JVM
  • Netty
  • Java各版本特性
  • 23种设计模式
  • Maven
  • Java常用框架
  • Dubbo
  • OpenFeign
  • Nacos
  • Zookeeper
  • Sentinel
  • Seata
  • Gateway
  • Go基础
  • Gin
  • SQL数据库

    • MySQL
    • Oracle
  • NoSQL数据库

    • Redis
    • MongoDB
    • ElasticSearch
  • 消息中间件

    • RabbitMQ
    • RocketMQ
    • Kafka
    • ActiveMQ
    • MQTT
    • NATS
  • 网关中间件

    • Nginx
  • Linux
  • Docker
  • Git
  • K8s
  • Solidity
  • Java
  • 计算机网络
  • 操作系统
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Gin 介绍
  • Gin 环境搭建
  • golang 程序的热加载
  • Gin 框架中的路由
  • Gin HTML 模板渲染
  • 静态文件服务
  • 路由详解
  • Gin 中自定义控制器
  • Gin 中间件
  • Gin 中自定义 Model
  • Gin 文件上传
  • Gin 中的 Cookie
  • Gin 中的 Session
  • Gin 中使用 GORM 操作 mysql 数据库
  • 原生 SQL 和 SQL 生成器
  • Gin 中使用 GORM 实现表关联查询
    • 1、一对一
    • 2、一对多
    • 3、多对多
  • GORM 中使用事务
  • Gin 中使用 go-ini 加载.ini 配置文件
  • 《Gin》笔记
Salmon
2025-04-05
目录

Gin 中使用 GORM 实现表关联查询

image-20250409005503469

官方文档:https://gorm.io/zh_CN/docs/has_many.html (opens new window)

# 1、一对一

如上图所示,一个文章只有一个分类,article 和 article_cate 之间是 1 对 1 的关系。

文章表中的 cate_id 保存着文章分类的 id。

如果我们想查询文章的时候同时获取文章分类,就涉及到 1 对 1 的关联查询。

foreignkey 指定当前表的外键、references 指定关联表中和外键关联的字段

Article

package models

type Article struct {
    Id          int         `json:"id"`
    Title       string      `json:"title"`
    Description int         `json:"description"`
    CateId      string      `json:"cate_id"`
    State       int         `json:"state"`
    ArticleCate ArticleCate `gorm:"foreignKey:CateId;references:Id"`
}

func (Article) TableName() string {
    return "article"
}

ArticleCate

package models

// ArticleCate 的结构体
type ArticleCate struct {
    Id    int    `json:"id"`
    Title string `json:"title"`
    State int    `json:"state"`
}

func (ArticleCate) TableName() string {
    return "article_cate"
}

1、查询所有文章以及文章对应的分类信息:

func (con ArticleController) Index(c *gin.Context) {
    var articleList []models.Article
    models.DB.Preload("ArticleCate").Limit(2).Find(&articleList)
    c.JSON(200, gin.H{"result": articleList})
}

**注意:**Preload("ArticleCate")里面的 ArticleCate 为 Article struct 中定义的属性 ArticleCate

返回 JSON 数据:

[
  {
    "id": 1,
    "title": "8 月份 CPI 同比上涨 2.8% 猪肉价格上涨 46.7%",
    "description": 0,
    "cate_id": "1",
    "state": 1,
    "ArticleCate": {
      "id": 1,
      "title": "国内",
      "state": 1
    }
  },
  {
    "id": 2,
    "title": "中国联通与中国电信共建共享 5G 网络 用户归属不变",
    "description": 0,
    "cate_id": "1",
    "state": 1,
    "ArticleCate": {
      "id": 1,
      "title": "国内",
      "state": 1
    }
  }
]

2、查询所有文章以及文章对应的分类信息 指定条件:

func (con ArticleController) Index2(c *gin.Context) {
    var articleList []models.Article
    models.DB.Preload("ArticleCate").Where("id>=?", 4).Find(&articleList)
    c.JSON(200, gin.H{ "result": articleList, })
}

返回数据:

[
  {
    "id": 4,
    "title": "这些老师的口头禅,想起那些年“被支配的恐惧”了吗",
    "description": 0,
    "cate_id": "2",
    "state": 1,
    "ArticleCate": {
      "id": 2,
      "title": "国际",
      "state": 1
    }
  },
  {
    "id": 5,
    "title": "美国空军一号差点遭雷劈,特朗普惊呼:令人惊奇",
    "description": 0,
    "cate_id": "3",
    "state": 1,
    "ArticleCate": {
      "id": 3,
      "title": "娱乐",
      "state": 1
    }
  }
]

# 2、一对多

1 对多在实际项目中用的非常多

  • 比如一个点餐系统:有菜品分类、有菜品。 菜品分类和菜品之间就是一对多的关系
  • 订单表和订单商品表:订单表和订单商品表之间也是一对多的关系

如上图所示,一个分类下面有很多个文章,article_cate 和 article 之间是 1 对多的关系。

文章表中的 cate_id 保存着文章分类的 id。

如果我们想查询文章分类的时候获取分类下面的文章,这个时候就涉及到一对多的关联查询。

ArticleCate

package models

// ArticleCate 的结构体
type ArticleCate struct {
    Id      int       `json:"id"`
    Title   string    `json:"title"`
    State   int       `json:"state"`
    Article []Article `gorm:"foreignKey:CateId"`
}

func (ArticleCate) TableName() string {
    return "article_cate"
}

Article

package models

type Article struct {
    Id          int    `json:"id"`
    Title       string `json:"title"`
    Description int    `json:"description"`
    CateId      string `json:"cate_id"`
    State       int    `json:"state"`
}

func (Article) TableName() string {
    return "article"
}

1、查找所有分类以及分类下面的文章信息

func (con ArticleController) Index3(c *gin.Context) {
    var articleCateList []models.ArticleCate
    models.DB.Preload("Article").Find(&articleCateList)
    c.JSON(200, gin.H{"result": articleCateList})
}

返回数据:

[
  {
    "id": 1,
    "title": "国内",
    "state": 1,
    "Article": [
      {
        "id": 1,
        "title": "8 月份 CPI 同比上涨 2.8% 猪肉价格上涨 46.7%",
        "description": 0,
        "cate_id": "1",
        "state": 1
      },
      {
        "id": 2,
        "title": "中国联通与中国电信共建共享 5G 网络 用户归属不变",
        "description": 0,
        "cate_id": "1",
        "state": 1
      }
    ]
  },
  {
    "id": 2,
    "title": "国际",
    "state": 1,
    "Article": [
      {
        "id": 3,
        "title": "林郑月娥斥责暴徒破坏港铁:不能因为没生命就肆意破坏",
        "description": 0,
        "cate_id": "2",
        "state": 1
      },
      {
        "id": 4,
        "title": "这些老师的口头禅,想起那些年“被支配的恐惧”了吗",
        "description": 0,
        "cate_id": "2",
        "state": 1
      }
    ]
  },
  ...
]

2、查找所有分类以及分类下面的文章信息 指定条件

func (con ArticleController) Index4(c *gin.Context) {
    var articleCateList []models.ArticleCate
    models.DB.Preload("Article").Where("id>0").Offset(1).Limit(1).Find(&articleCateList)
    c.JSON(200, gin.H{"result": articleCateList})
}

返回数据:

[
  {
    "id": 2,
    "title": "国际",
    "state": 1,
    "Article": [
      {
        "id": 3,
        "title": "林郑月娥斥责暴徒破坏港铁:不能因为没生命就肆意破坏",
        "description": 0,
        "cate_id": "2",
        "state": 1
      },
      {
        "id": 4,
        "title": "这些老师的口头禅,想起那些年“被支配的恐惧”了吗",
        "description": 0,
        "cate_id": "2",
        "state": 1
      }
    ]
  }
]

3、更多 1 对多的查询方法

地址:https://github.com/jouyouyun/examples/tree/master/gorm/related (opens new window)

4、如果我们的程序中有如下需求

  1. 查询文章获取文章分类信息
  2. 查询文章分类获取文章信息

这个时候可以这样定义 models

package models

type Article struct {
    Id          int    `json:"id"`
    Title       string `json:"title"`
    Description int    `json:"description"`
    CateId      string `json:"cate_id"`
    State       int    `json:"state"`
    ArticleCate ArticleCate `gorm:"foreignKey:CateId;references:Id"`
}

func (Article) TableName() string {
    return "article"
}
package models

// ArticleCate 的结构体
type ArticleCate struct {
    Id      int       `json:"id"`
    Title   string    `json:"title"`
    State   int       `json:"state"`
    Article []Article `gorm:"foreignKey:CateId"`
}

func (ArticleCate) TableName() string {
    return "article_cate"
}

# 3、多对多

image-20250409005721449

1、定义学生 课程 学生课程表 model

如果想根据课程获取选学本门课程的学生,这个时候就在 Lesson 里面关联 Student

Lesson

package models

type Lesson struct {
    Id      int        `json:"id"`
    Name    string     `json:"name"`
    Student []*Student `gorm:"many2many:lesson_student"`
}

func (Lesson) TableName() string {
    return "lesson"
}

Student

package models

type Student struct {
    Id       int
    Number   string
    Password string
    ClassId  int
    Name     string
    Lesson   []*Lesson `gorm:"many2many:lesson_student"`
}

func (Student) TableName() string {
    return "student"
}

LessonStudent

package models

type LessonStudent struct {
    LessonId  int
    StudentId int
}

func (LessonStudent) TableName() string {
    return "lesson_student"
}

2、获取学生信息 以及课程信息

func (con StudyController) test1(c *gin.Context) {
    var studentList []models.Student
    models.DB.Find(&studentList)
    c.JSON(http.StatusOK, studentList)
}

func (con StudyController) test2(c *gin.Context) {
    var lessonList []models.Lesson
    models.DB.Find(&lessonList)
    c.JSON(http.StatusOK, lessonList)
}

3、查询学生信息的时候获取学生的选课信息

func (con StudyController) test3(c *gin.Context) {
    var studentList []models.Student
    models.DB.Preload("Lesson").Find(&studentList)
    c.JSON(http.StatusOK, studentList)
}

4、查询张三选修了哪些课程

func (con StudyController) test4(c *gin.Context) {
    var studentList []models.Student
    models.DB.Preload("Lesson").Where("id=1").Find(&studentList)
    c.JSON(http.StatusOK, studentList)
}

5、课程被哪些学生选修了

func (con StudyController) test5(c *gin.Context) {
    var lessonList []models.Lesson
    models.DB.Preload("Student").Find(&lessonList)
    c.JSON(http.StatusOK, lessonList)
}

6、计算机网络被那些学生选修了

func (con StudyController) test6(c *gin.Context) {
    var lessonList []models.Lesson
    models.DB.Preload("Student").Where("id=1").Find(&lessonList)
    c.JSON(http.StatusOK, lessonList)
}

7、查询数据指定条件

func (con StudyController) test7(c *gin.Context) {
    var lessonList []models.Lesson
    models.DB.Preload("Student").Offset(1).Limit(2).Find(&lessonList)
    c.JSON(http.StatusOK, lessonList)
}

8、关联查询指定子集的筛选条件

https://gorm.io/zh_CN/docs/preload.html (opens new window)

张三被开除了 查询课程被哪些学生选修的时候要去掉张三

用法:

func (con StudyController) test8(c *gin.Context) {
    var access []models.Access
    models.DB.Preload("AccessItem", "status=1").Order("sort desc").Where("module_id=?", 0).Find(&access)
    var lessonList []models.Lesson
    models.DB.Preload("Student", "id!=1").Find(&lessonList)
    c.JSON(http.StatusOK, lessonList)
}
func (con StudyController) test9(c *gin.Context) {
    var lessonList []models.Lesson
    models.DB.Preload("Student", "id not in (1,2)").Find(&lessonList)
    c.JSON(http.StatusOK, lessonList)
}

9、自定义预加载 SQL

查看课程被哪些学生选修 要求:学生 id 倒叙输出

https://gorm.io/zh_CN/docs/preload.html (opens new window)

**注意:**需要引入 gorm.io/gorm 这个包

func (con StudyController) test10(c *gin.Context) {
    var lessonList []models.Lesson
    models.DB.Preload("Student", func(db *gorm.DB) *gorm.DB {
       return models.DB.Order("id DESC")
    }).Find(&lessonList)
    c.JSON(http.StatusOK, lessonList)
}
func (con StudyController) test11(c *gin.Context) {
    var lessonList []models.Lesson
    models.DB.Preload("Student", func(db *gorm.DB) *gorm.DB {
       return models.DB.Where("id>3").Order("id DESC")
    }).Find(&lessonList)
    c.JSON(http.StatusOK, lessonList)
}
上次更新: 2025/04/11, 00:13:59
原生 SQL 和 SQL 生成器
GORM 中使用事务

← 原生 SQL 和 SQL 生成器 GORM 中使用事务→

Theme by Vdoing | Copyright © 2022-2025 Salmon's Blog
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式