[golang gin框架] 8.Gin GORM原生 SQL以及表关联查询

本文介绍了如何在Gin框架中使用GORM库进行原生SQL的删除、修改、查询和统计操作,以及如何实现一对一、一对多和多对多的关联查询。示例包括文章和分类的关联,展示了Preload方法在加载关联数据时的应用。
摘要由CSDN通过智能技术生成

1.原生 SQL 和 SQL 生成器

(1).使用原生 sql 删除 user 表中的一条数据

result := models.DB.Exec("delete from user where id=?", 3)
fmt.Println(result.RowsAffected)

(2).使用原生 sql 修改 user 表中的一条数据

result := models.DB.Exec("update user set username=? where id=2", "哈哈")
fmt.Println(result.RowsAffected)

(3).查询 uid=2 的数据

var result models.User
models.DB.Raw("SELECT * FROM user WHERE id = ?", 2).Scan(&result)
fmt.Println(result)

(4).查询 User 表中所有的数据

var result []models.User
models.DB.Raw("SELECT * FROM user").Scan(&result)
fmt.Println(result)

(5).统计 user 表的数量

var count int
row := models.DB.Raw("SELECT count(1) FROM user").Row(&count )
row.Scan(&count)

更多使用方法:https://gorm.io/zh_CN/docs/sql_builder.html

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

(1).一对一

如上图所示,一个文章只有一个分类,article 和 article_cate 之间是 1 对 1 的关系,文章表中的 cate_id 保存着文章分类的 id,如果我们想查询文章的时候同时获取文章分类,就涉及到 1 对 1 的关联查询.
foreignkey 指定当前表的外键、 references 指定关联表中和外键关联的字段

Article.go模型

package models

//文章

type Article struct { // 结构体首字母大写, 和数据库表名对应, 默认访问数据表users, 可以设置访问数据表的方法
    Id     int    `json:"id"`
    Title  string `json:"title"`
    CateId int    `json:"cate_id"`  // 该键是文章分类的外键, 如果该键是ArticleCateId,那么就会直接和ArticleCate.Id建立关系
    State  int    `json:"state"`
    ArticleCate ArticleCate   `gorm:"foreignKey:CateId"` // 使用 CateId 作为外键 // 和文章分类建立关系
}

//配置数据库操作的表名称
func (Article) TableName() string {
    return "article"
}

ArticleCate.go模型

package models

//文章分类

type ArticleCate struct { // 结构体首字母大写, 和数据库表名对应, 默认访问数据表users, 可以设置访问数据表的方法
    Id      int       `json:"id"` // 主键, 可用于和其他数据表建立关系,
    Title   string    `json:"title"`
    State   int       `json:"state"`
 }

//配置数据库操作的表名称
func (ArticleCate) TableName() string {
    return "article_cate"
}

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

func (con ArticleController) Index(c *gin.Context) {
    //定义文章结构体切片
    articleList := []models.Article{}
    //查询所有文章,以及文章的分类Preload
    models.DB.Preload("ArticleCate").Where("state = ?", 1).Find(&articleList)
    c.JSON(http.StatusOK, gin.H{
        "result": articleList,
    })
    c.JSON(http.StatusOK, gin.H{
        "result": articleCateList,
    })
}
注意:Preload("ArticleCate")里面的 ArticleCate 为 Article struct 中定义的属性 ArticleCate

返回 JSON 数据

[
    { 
        "id": 1, 
        "title": "xxx",
        "description": 0,
        "cate_id": "1", 
        "state": 1, 
        "ArticleCate": {
             "id": 1, 
             "title": "国内", 
             "state": 1
     },
     ...
}

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

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

(2).一对多

对多在实际项目中用的非常多: 比如一个点餐系统:有菜品分类、有菜品。 菜品分类和菜品之间就是一对多的关系; 订单表和订单商品表:订单表和订单商品表之间也是一对多的关系;如上图所示,一个分类下面有很多个文章,article_cate 和 article 之间是一对多的关系,文章表中的 cate_id 保存着文章分类的 id.如果想查询文章分类的时候获取分类下面的文章,这个时候就涉及到一对多的关联查
询,那么ArticleCate.go模型就要修改一下,看下面的代码:
package models

//文章分类

type ArticleCate struct { // 结构体首字母大写, 和数据库表名对应, 默认访问数据表users, 可以设置访问数据表的方法
    Id      int       `json:"id"` // 主键, 可用于和其他数据表建立关系,
    Title   string    `json:"title"`
    State   int       `json:"state"`
    //foreignKey: 外键,如果是表名称加上Id,默认也可以不配置,如果不是,则需要通过foreignKey配置外键名称
    //references: 主键,默认是Id,如果是Id,默认也可以不配置
    Article []Article `gorm:"foreignKey:CateId;references:Id"` // 关联分类的所有文章
}

//配置数据库操作的表名称
func (ArticleCate) TableName() string {
    return "article_cate"
}

ArticleController.go控制器代码如下:

func (con ArticleController) Index(c *gin.Context) { 
    //定义文章分类结构体切片
    articleCateList := []models.ArticleCate{}
    //查询所有文章分类,以及文章分类对应的所有文章数据
    models.DB.Preload("Article").Where("state = ?", 1).Find(&articleCateList)
    c.JSON(http.StatusOK, gin.H{
        "result": articleCateList,
    })
}

返回的json数据如下:

[
    { 
    "id": 1,
    "title": "国内", 
    "state": 1, 
    "Article": [
        { 
            "id": 1, 
            "title": "xxx", 
            "description": 0,
            "cate_id": "1", 
            "state": 1
        },
        { 
            "id": 2, 
            "title": "xxx", 
            "description": 0, 
            "cate_id": "1",
            "state": 1
        },
        ...
     ],
    },
    ...
]

更多使用方法:https://gorm.io/zh_CN/docs/has_many.html, https://github.com/jouyouyun/examples/tree/master/gorm/related

(3).多对多

一个学生可以选修多门课程,一门课程可以被多个学生选修,这就是一个典型的多对多的案例,这需要三个相关数据表,一个是学生表(student),保存的是学生基本信息,一个是课程表(lession).保存的是课程相关信息,最后一个是课程-学生关联表(lession_student),保存的是课程-学生选修关系的数据信息,代码如下:

模型代码如下:

Lession.go
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.go
package models

// 学生模型

type Student struct {
    Id     int    `json:"id"`  
    Number  string `json:"number"`
    Password string    `json:"password"`
    ClassId  int    `json:"class_id"`
    Name  string    `json:"name"`
    Lesson []Lesson   `gorm:"many2many:lesson_student;"`
}

//配置数据库操作的表名称
func (Student) TableName() string {
    return "student"
}
LessonStudent.go
package models

//课程-学生关系模型

type LessonStudent struct {
    LessonId      int       `json:"lesson_id"`
    StudentId      int       `json:"student_id"`
}

//配置数据库操作的表名称
func (LessonStudent) TableName() string {
    return "lesson_student"
}

控制器代码:


package admin

import (
    "gindemo/models"
    "github.com/gin-gonic/gin"
    "gorm.io/gorm"
    "net/http"
)

//定义一个StudentController结构体,可以实例化结构体访问里面的方法
type StudentController struct {
    BaseController  // 继承基础控制器
}

//列表
func (con StudentController) Index(c *gin.Context) {
    //获取所有学生信息
    StudentList := []models.Student{}
    models.DB.Find(&StudentList)
    c.JSON(http.StatusOK, gin.H{
        "获取所有学生信息": StudentList,
    })

    //获取所有课程信息
    LessonList := []models.Lesson{}
    models.DB.Find(&LessonList)
    c.JSON(http.StatusOK, gin.H{
        "获取所有课程信息": LessonList,
    })

    //查询学生信息的时候,展示学生选修的课程
    StudentLessonList := []models.Student{}
    models.DB.Preload("Lesson").Find(&StudentLessonList)
    c.JSON(http.StatusOK, gin.H{
        "查询学生信息的时候,展示学生选修的课程": StudentLessonList,
    })

    //查询某个学生的选修课程信息
    StudentOneList := []models.Student{}
    models.DB.Preload("Lesson").Where("name = ?", "张三").Find(&StudentOneList)
    c.JSON(http.StatusOK, gin.H{
        "查询某个学生的选修课程信息": StudentOneList,
    })

    //查询课程被哪些学生选修了
    LessonStudentList := []models.Lesson{}
    models.DB.Preload("Student").Find(&LessonStudentList)
    c.JSON(http.StatusOK, gin.H{
        "查询课程被哪些学生选修了": LessonStudentList,
    })

    //查询某个课程被哪些学生选修了
    LessonStudentOneList := []models.Lesson{}
    models.DB.Preload("Student").Where("name = ?", "计算机网络").Find(&LessonStudentOneList)
    c.JSON(http.StatusOK, gin.H{
        "查询某个课程被哪些学生选修了": LessonStudentOneList,
    })

    //查询指定条件
    LessonCondition := []models.Lesson{}
    models.DB.Preload("Student").Offset(1).Limit(2).Where("name = ?", "计算机网络").Find(&LessonCondition)
    c.JSON(http.StatusOK, gin.H{
        "查询指定条件": LessonCondition,
    })

    //查询课程时候,排除某个学生
    LessonNot := []models.Lesson{}
    //models.DB.Preload("Student", "id != ?", 1).Find(&LessonNot) // id 不等于某个学生
    models.DB.Preload("Student", "id not in (1, 2)?").Find(&LessonNot) // id 不等于某些学生
    c.JSON(http.StatusOK, gin.H{
        "查询课程时候,排除某个学生": LessonNot,
    })

    //预加载sql:需要引入 gorm.io/gorm 这个包
    LessonByStudentOrder := []models.Lesson{}
    models.DB.Preload("Student", func(db *gorm.DB) *gorm.DB {
        return models.DB.Where("id > 3").Order("student.id DESC")
    }).Find(&LessonByStudentOrder)
    c.JSON(http.StatusOK, gin.H{
        "预加载sql,按学生id降序排列": LessonByStudentOrder,
    })
}
注意:
上面的预加载sql操作中,需要引入 gorm.io/gorm 这个包

更多操作,请看:

预加载: https://gorm.io/zh_CN/docs/preload.html

Many To Many: https://gorm.io/zh_CN/docs/many_to_many.html

[上一节][golang gin框架] 7.Gin GORM增删改查以及查询语句详解

[下一节][golang gin框架] 9.Gin GORM 中使用事务以及go-ini加载.ini配置文件

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值