GORM 多对多many2many 自定义连接表

文章目录

  • 多对多 many2many
    • 表结构搭建
    • 多对多添加
    • 多对多查询
    • 多对多的删除、更新
  • 自定义连接表
    • 生成表结构
    • 操作案例
      • 添加文章并添加标签,并自动关联
      • 添加文章,关联已有标签
      • 给已有文章关联标签
      • 替换已有文章的标签
      • 查询文章列表,显示标签
    • 自定义连接表主键
    • 操作连接表
      • 查询

多对多 many2many

Many to Many 会在两个 model 中添加一张连接表,将不同表的id连接起来,也就是说 总共三张表
我们这里以文章和其tag为例,一篇文章可以有多个tag,一个tag中也有多个文章

表结构搭建

type Article struct {ID    uint   `gorm:"size:8"`Title string `gorm:"size:16"`Tags  []Tag  `gorm:"many2many:article_tags;"` //用于确定多对多的关系并指定第三张连接表的名字
}
type Tag struct {ID       uint      `gorm:"size:8"`Text     string    `gorm:"size:16"`Articles []Article `gorm:"many2many:article_tags;"`//反向引用,可以用来查询具有相同标签的文章
}DB.AutoMigrate(&Article{}, &Tag{})

搭建表结构如图:
在这里插入图片描述

多对多添加

创建标签和文章:
  建立一篇标题为“go”的文章,并新建标签为studylanguage

DB.Save(&Article{ID:    1,Title: "go",Tags: []Tag{{Text: "language"},{Text: "study"},},
})

添加文章,选择标签:这里以选择单个标签为例
如果不查询,即使标签名字一致也会重建一个新的标签

var tag Tag
DB.Take(&tag, "Text=?", "study")
DB.Save(&Article{Title: "Study notes",Tags:  []Tag{tag},
})

多对多查询

//查询文章,显示文章的标签列表
var article Article
DB.Preload("Tags").Take(&article, 1)
fmt.Println(article)//查询标签,显示具有该标签的文章列表
var tag Tag
DB.Preload("Articles").Take(&tag, 2)
fmt.Println(tag)

多对多的删除、更新

移除文章的标签

var article Article
DB.Preload("Tags").Take(&article, 1)
DB.Model(&article).Association("Tags").Delete(article.Tags)
fmt.Println(article)

跟新文章的标签

article = Article{}
var tags []TagDB.Find(&tags, []int{1, 2, 3}) //找到想要添加的标签DB.Preload("Tags").Take(&article, 1) //预加载要修改的文章DB.Model(&article).Association("Tags").Replace(tags) //替换文章标签

自定义连接表

默认的连接表,只有双方的主键id,展示不了更多信息了,为了

type Article struct {ID    uintTitle stringTags  []Tag `gorm:"many2many:article2tag;"`
}type Tag struct {ID   uintText string//Articles []Article `gorm:"many2many:article2tag;"` //当使用反向引用时需要在setUpJoinTable时多设置一次这个表的 @@@
}// Article2tag 自定义连接表
type Article2tag struct {ArticleID uint      `gorm:"primaryKey"`TagID     uint      `gorm:"primaryKey "` //上两项即为连接表默认项CreatedAt time.Time //自定义添加一个创建时间字段
}

生成表结构

//第一个参数为具有连接另一个表的字段的连接表,第二个即为连接字段的字段名,第三个为连接表
DB.SetupJoinTable(&Article{}, "Tags", &Article2tag{})
//DB.SetupJoinTable(&Tag{}, "Articles", &Article2tag{}) //与上面反向引用时对应 @@@
DB.AutoMigrate(&Article{}, &Tag{}, &Article2tag{})

操作案例

  我们如果在自定义连接表中设置了默认字段之外的字段的话,需要使用添加钩子beforeCreate来赋值,这里的createAt字段gorm会自动填充,关于钩子函数
  SetupJoinTable:添加和更新是不能注释掉这个,这样才能走自定义的连接表,以及走他的钩子函数,查询则不需要

添加文章并添加标签,并自动关联

DB.Create(&Article{Title: "golang_study",Tags: []Tag{{Text: "go"},{Text: "study"}},})

添加文章,关联已有标签

//添加文章,关联已有标签
var tag Tag
DB.Take(&tag, "text=?", "study")
DB.Create(&Article{Title: "how To Study",Tags:  []Tag{tag},
})

给已有文章关联标签

//直接操作连接表,比较极端,知道文章和tag的ID,直接进行添加-------------
DB.Create(&Article2tag{ArticleID: 3,TagID:     2,CreatedAt: time.Time{},
})//先查询相关标签,在关联--------------------
var tags []Tag //这里主要根据tag切片作为识别,切片名字可以随便起
DB.Find(&tags, "text in?", []string{"go", "study"})var article Article
DB.Take(&article, "title=?", "gin")DB.Model(&article).Association("Tags").Append(&tags)

替换已有文章的标签

//替换已有文章的标签
var article Article
DB.Preload("Tags").Take(&article, 3) //preload中参数需严格对应,这里不需要preload好像也可以:) 
fmt.Println(article)
var tag Tag
DB.Take(&tag, "text=?", "go")
DB.Model(&article).Association("Tags").Replace(&tag)

查询文章列表,显示标签

//查询文章列表并显示标签
var articles []Article
DB.Preload("Tags").Find(&articles)
fmt.Println(articles)

自定义连接表主键

  当定义的表复杂时,gorm自动的主键名可能比较冗长,我们可以通过自定义主键名来简单化
主要要注释的是joinForeignKey 连接主键ID
            joinReferences 关联主键ID

// 自定义主键部分-----------------------------------------
type Article struct {ID    uintTitle stringTags  []Tag `gorm:"many2many:article2tag;joinForeignKey:A_ID;joinReferences:T_ID"`
}type Tag struct {ID       uintText     stringArticles []Article `gorm:"many2many:article2tag;joinForeignKey:T_ID;joinReferences:A_ID"` //当使用反向引用时需要在setUpJoinTable时多设置一次这个表的 @@@
}// Article2tag 自定义连接表
type Article2tag struct {A_ID      uint      `gorm:"primaryKey"`T_ID      uint      `gorm:"primaryKey "` //上两项即为连接表默认项CreatedAt time.Time //自定义添加一个创建时间字段
}

操作连接表

  当通过其他表来查连接表,可能会不方便,比如我们在这里查二者什么时候建立的关联,即createat字段名

查询

传统查询文章列表,显示标签
首先其无法进行分页操作,经过如下修改,也能分页

DB.Preload("Tags").Take(&article, 1)
var tags []Tag
DB.Model(article).Limit(1).Association("Tags").Find(&tags) //这样可以分页,但是也无法查询连接表中其他字段,如关联时间
fmt.Println(tags)

若是直接在此时的连接表查询,我们也只能得到文章和标签的id,无法得到用户名及标签名
因此我们可以改一下连接表结构,将两张主表的结构体关联到连接表中,具体可见如下代码所示:

// Article2tag 自定义连接表
type Article2tag struct {ArticleID uint    `gorm:"primaryKey"`TagID     uint    `gorm:"primaryKey "` //上两项即为连接表默认项Article   Article `gorm:"foreignKey:ArticleID"`Tag       Tag     `gorm:"foreignKey:TagID"`CreatedAt time.Time //自定义添加一个创建时间字段
}

查询相关写法可以参见该 链接

var articleTag []Article2tag
DB.Preload("Article").Preload("Tag").Where(map[string]any{"Article_id": 1}).Find(&articleTag) //大小写可忽略,符号不可忽略,具体需查看表内字段
fmt.Println(articleTag)
DB.Preload("Article").Preload("Tag").Where("article_id=?", 1).Find(&articleTag) //大小写可忽略,符号不可忽略,具体需查看表内字段
fmt.Println(articleTag)
DB.Preload("Article").Preload("Tag").Find(&articleTag, "article_id=?", 1) //大小写可忽略,符号不可忽略,具体需查看表内字段
fmt.Println(articleTag)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/197491.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在 Mac 上使用浅色或深色外观

在 Mac 上,选取苹果菜单 >“系统设置”,然后点按边栏中的“外观” 。(你可能需要向下滚动。)选择右侧的“浅色”、“深色”或“自动”。 “浅色”表示不会发生变化的浅色外观。 “深色”表示不会发生变化的深色外观。“深色模式…

uniapp 之 短信验证码登录

一、需求 输入手机号码&#xff0c;可以获取验证码。 二、实现效果 点击前&#xff1a; 点击后&#xff1a; 三、代码实现 <template><view class"login"><view class"infobox"><view class"item"><input type…

使用Java语言判断一个数据类型是奇数还是偶数

判断一个数字类型是奇数&#xff0c;还是偶数&#xff0c;只需要引入Scanner类&#xff0c;然后按照数据类型的定义方式进行定义&#xff0c;比较是按照与2进行整除后的结果&#xff1b;如果余数为零&#xff0c;则代表为偶数&#xff0c;否则为奇数。 import java.util.Scann…

★136. 只出现一次的数字(位运算)

136. 只出现一次的数字 这个题主要考察的知识点是位运算&#xff08;这里是异或&#xff09; 如果不要求空间复杂度为O&#xff08;1&#xff09;&#xff0c;那有很多方法。但是这里有这样的要求。 可以通过位运算 的方法来实现。 异或运算 ⊕有以下三个性质&#xff1a; 任…

数据分析师的学习之路-pandas篇(6)

接上篇&#xff0c;画图告一段落&#xff0c;现在学习表格的各种操作。 3.8 表格操作 3.8.1 表的校验 表里有些列的数据是有一定的要求的&#xff0c;比如说下面这个表&#xff0c;Score分数列&#xff0c;要求成绩只能是0到100&#xff0c;那如果有出现错误的数据&#xff0…

Swift 常用关键字

目录 一、数据类型 1. 流程控制 2. 访问控制 3. 功能修饰词 4. 错误处理 5. 泛型和类型 6. 其它关键字 二、部分关键字说明 1. guard 2. class 和 struct struct&#xff08;结构体&#xff09; class&#xff08;类&#xff09; 使用场景 3. mutating 4. proto…

【算法专题】前缀和

前缀和 前缀和1. 前缀和【模板】2. 二维前缀和【模板】3. 寻找数组的中心下标4. 除自身以外数组的乘积5. 和为K的子数组6. 和可被K整除的子数组7. 连续数组8. 矩阵区域和 前缀和 1. 前缀和【模板】 题目链接 -> Nowcoder -DP34.前缀和【模板】 Nowcoder -DP34.前缀和【模…

nodejs微信小程序+python+PHP天天网站书城管理系统的设计与实现-计算机毕业设计推荐

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

matlab实践(九):分段线性插值与三次样条插值

题目 用matlab对572所在区间分别进行分段线性插值、三次样条插值&#xff0c;计算出151&#xff0c;159&#xff0c;984&#xff0c;995的对数值&#xff0c;画出图形并在图形上用红色圆圈标记151&#xff0c;159&#xff0c;984&#xff0c;995所在的点,同时在图形中显示这些…

Java Socket编程之基于TCP协议通信

1.说明 Socket&#xff08;套接字&#xff09;是计算机网络编程中用于实现网络通信的一种编程接口或抽象概念。 它提供了一种标准的接口&#xff0c;使应用程序能够通过网络与其他计算机进行通信。 Socket可以看作是应用程序与网络之间的一个通信端点&#xff0c;类似于电话中…

如何在 Chrome 上调试文件打断点

1. 控制台进入 Source 2. CtrlP 输入文件名称 3. 在需要的位置手动打断点 4. 重新触发代码运行&#xff0c;触发断点

分享 | 顶刊高质量论文插图配色(含RGB值及16进制HEX码)(第一期)

我在很早之前出过一期高质量论文绘图配色&#xff0c;但当时觉得搜集太麻烦于是就没继续做&#xff0c;后来用MATLAB爬了上万张顶刊绘图&#xff0c;于是又想起来做这么一个系列&#xff0c;拿了一个多小时写了个提取论文图片颜色并得出RGB值和16进制码并标注在原图的代码&…

简单了解传输层协议之TCP和UDP

目录 一、什么是端口号? 二、TCP协议 2.1 TCP报文格式 2.2 三次握手 2.3 四次挥手 2.4 窗口流量控制 三、UDP协议 3.1 UDP报文格式 3.4 传输过程 一、什么是端口号? 我们自己的一台电脑上有时可能会同时运行多个进程软件来进行上网。那么当网络上的服务器响应我们电…

Chrome清除特定网站的Cookie,从而让网址能正常运行(例如GPT)

Chrome在使用某些网址的时候&#xff0c;例如GPT的时候&#xff0c;可能会出现无法访问这个网址的情况&#xff0c;就是点不动啥的 只需要把你需要重置的网址删除就好了

C语言小游戏:三子棋

目录 &#x1f30d;前言 &#x1f685;目录设计 &#x1f48e;游戏逻辑设置 ⚔三子棋棋盘设计 ⚔三子棋运行逻辑 &#x1f440;怎么设置人下棋 &#x1f440;怎么设置电脑下棋 ✈如何判断输赢 ✍结语 &#x1f30d;前言 Hello,csdn的各位小伙伴你们好啊!这次小赵给大…

根据源码梳理Redisson的可重入、锁重试以及看门狗机制原理

Redisson可重入的原理 在上篇文章中我们已经知道了除了需要存储线程标识外&#xff0c;会额外存储一个锁重入次数。那么接下来我们查看使用Redisson时&#xff0c;Redisson的加锁与释放锁流程图。 当开始获取锁时&#xff0c;会先判断锁是否存在&#xff0c;如果存在再进行判断…

算法通关村第十六关-黄金挑战滑动窗口与堆的结合

大家好我是苏麟 , 今天带来一道小题 . 滑动窗口最大值 描述 : 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 题目 : …

EM32DX-C4【C#】

1外观&#xff1a; J301 直流 24V 电源输入 CAN0 CAN0 总线接口 CAN1 CAN1 总线接口 J201 IO 接线段子 S301-1、S301-2 输出口初始电平拨码设置 S301-3~S301-6 模块 CAN ID 站号拨码开关 S301-7 模块波特率拨码设置 S301-8 终端电阻选择开关 2DI&#xff1a; 公共端是…

XUbuntu22.04之OBS30.0设置录制音频降噪(一百九十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

LLM之Agent(三):HuggingGPT根据用户需求自动调用Huggingface合适的模型

​ 浙大和微软亚洲研究院开源的HuggingGPT&#xff0c;又名JARVIS&#xff0c;它可以根据用户的自然语言描述的需求就可以自动分析需要哪些AI模型&#xff0c;然后去Huggingface上直接调用对应的模型&#xff0c;最终给出用户的解决方案。 一、HuggingGPT的工作流程 它的…