gorm使用之各种表关系实例-主外键->struct

gorm使用之各种表关系实例-主外键->struct

一对多关系(用户与文章)

如:

老板与员工
女神和舔狗
老师和学生
班级与学生
用户与文章
...

以用户与文章举例

models应当如,注意!!:User表中的ID应当与Article中的UID一直,大小和注释都得一只

package models

type User struct {
	ID       uint      
	Name     string    `gorm:"size:8"`
	Articles []Article `gorm:"foreignKey:UID"` // 用户拥有的文章列表
}

type Article struct {
	ID    uint   `gorm:"size:4"`
	Title string `gorm:"size:16"`
	UID   uint   // 属于
	User  User   `gorm:"foreignKey:UID"` // 属于
}

联表实例

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image2

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Image5

一对一关系(用户与用户详情)

一对一关系比较少,一般用于表的扩展

例如一张用户表,有很多字段

那么就可以把它拆分为两张表,常用的字段放主表,不常用的字段放详情表

表结构搭建

type User struct {
  ID       uint
  Name     string
  Age      int
  Gender   bool
  UserInfo UserInfo // 通过UserInfo可以拿到用户详情信息
}

type UserInfo struct {
  UserID uint // 外键
  ID     uint
  Addr   string
  Like   string
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

添加用户详情,关联已有用户

这个场景特别适合网站的注册,以及后续信息完善

刚开始注册的时候,只需要填写很基本的信息,这就是添加主表的一条记录

注册进去之后,去个人中心,添加头像,修改地址…

这就是添加附表

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

DB.Create(&UserInfo{
  UserID: 2,
  Addr:   "南京市",
  Like:   "吃饭",
})

Image8

一般是主表查附表

var user User
DB.Preload("UserInfo").Take(&user)
fmt.Println(user)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

多对多关系(文章标签,文章标签表)

多对多关系,需要用第三张表存储两张表的关系

假设表结构如:

type Article struct {
  ID    uint
  Title string
  Tags  []Tag `gorm:"many2many:article_tags"`
}

type Tag struct {
  ID   uint
  Name string
}

type ArticleTag struct {
  ArticleID uint `gorm:"primaryKey"`
  TagID     uint `gorm:"primaryKey"`
  CreatedAt time.Time
}

生成表结构

// 设置Article的Tags表为ArticleTag
DB.SetupJoinTable(&Article{}, "Tags", &ArticleTag{})
// 如果tag要反向应用Article,那么也得加上
// DB.SetupJoinTable(&Tag{}, "Articles", &ArticleTag{})
err := DB.AutoMigrate(&Article{}, &Tag{}, &ArticleTag{})
fmt.Println(err)

操作案例

举一些简单的例子

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

  2. 添加文章,关联已有标签

  3. 给已有文章关联标签

  4. 替换已有文章的标签

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

DB.SetupJoinTable(&Article{}, "Tags", &ArticleTag{})  // 要设置这个,才能走到我们自定义的连接表
DB.Create(&Article{
  Title: "flask零基础入门",
  Tags: []Tag{
    {Name: "python"},
    {Name: "后端"}, 
    {Name: "web"},
  },
})
// CreatedAt time.Time 由于我们设置的是CreatedAt,gorm会自动填充当前时间,
// 如果是其他的字段,需要使用到ArticleTag 的添加钩子 BeforeCreate
  1. 添加文章,关联已有标签
DB.SetupJoinTable(&Article{}, "Tags", &ArticleTag{})
var tags []Tag
DB.Find(&tags, "name in ?", []string{"python", "web"})
DB.Create(&Article{
  Title: "flask请求对象",
  Tags:  tags,
})
  1. 给已有文章关联标签
DB.SetupJoinTable(&Article{}, "Tags", &ArticleTag{})
article := Article{
  Title: "django基础",
}
DB.Create(&article)
var at Article
var tags []Tag
DB.Find(&tags, "name in ?", []string{"python", "web"})
DB.Take(&at, article.ID).Association("Tags").Append(tags)
  1. 替换已有文章的标签
var article Article
var tags []Tag
DB.Find(&tags, "name in ?", []string{"后端"})
DB.Take(&article, "title = ?", "django基础")
DB.Model(&article).Association("Tags").Replace(tags)
  1. 查询文章列表,显示标签
var articles []Article
DB.Preload("Tags").Find(&articles)
fmt.Println(articles)

自定义连接表主键

这个功能还是很有用的,例如你的文章表 可能叫ArticleModel,你的标签表可能叫TagModel

那么按照gorm默认的主键名,那就分别是ArticleModelID,TagModelID,太长了,根本就不实用

这个地方,官网给的例子看着也比较迷,不过我已经跑通了

主要是要修改这两项

joinForeignKey 连接的主键id

JoinReferences 关联的主键id

type ArticleModel struct {
  ID    uint
  Title string
  Tags  []TagModel `gorm:"many2many:article_tags;joinForeignKey:ArticleID;JoinReferences:TagID"`
}

type TagModel struct {
  ID       uint
  Name     string
  Articles []ArticleModel `gorm:"many2many:article_tags;joinForeignKey:TagID;JoinReferences:ArticleID"`
}

type ArticleTagModel struct {
  ArticleID uint `gorm:"primaryKey"` // article_id
  TagID     uint `gorm:"primaryKey"` // tag_id
  CreatedAt time.Time
}

生成表结构

DB.SetupJoinTable(&ArticleModel{}, "Tags", &ArticleTagModel{})
DB.SetupJoinTable(&TagModel{}, "Articles", &ArticleTagModel{})
err := DB.AutoMigrate(&ArticleModel{}, &TagModel{}, &ArticleTagModel{})
fmt.Println(err)

添加,更新,查询操作和上面的都是一样

操作连接表

如果通过一张表去操作连接表,这样会比较麻烦

比如查询某篇文章关联了哪些标签

或者是举个更通用的例子,用户和文章,某个用户在什么时候收藏了哪篇文章

无论是通过用户关联文章,还是文章关联用户都不太好查

最简单的就是直接查连接表

type UserModel struct {
  ID       uint
  Name     string
  Collects []ArticleModel `gorm:"many2many:user_collect_models;joinForeignKey:UserID;JoinReferences:ArticleID"`
}

type ArticleModel struct {
  ID    uint
  Title string
  // 这里也可以反向引用,根据文章查哪些用户收藏了
}

// UserCollectModel 用户收藏文章表
type UserCollectModel struct {
  UserID    uint `gorm:"primaryKey"` // article_id
  ArticleID uint `gorm:"primaryKey"` // tag_id
  CreatedAt time.Time
}

func main() {
  DB.SetupJoinTable(&UserModel{}, "Collects", &UserCollectModel{})
  err := DB.AutoMigrate(&UserModel{}, &ArticleModel{}, &UserCollectModel{})
  fmt.Println(err)
}

常用的操作就是根据用户查收藏的文章列表

var user UserModel
DB.Preload("Collects").Take(&user, "name = ?", "枫枫")
fmt.Println(user)

但是这样不太好做分页,并且也拿不到收藏文章的时间

var collects []UserCollectModel
DB.Find(&collects, "user_id = ?", 2)
fmt.Println(collects)

这样虽然可以查到用户id,文章id,收藏的时间,但是搜索只能根据用户id搜,返回也拿不到用户名,文章标题等

我们需要改一下表结构,不需要重新迁移,加一些字段

type UserModel struct {
  ID       uint
  Name     string
  Collects []ArticleModel `gorm:"many2many:user_collect_models;joinForeignKey:UserID;JoinReferences:ArticleID"`
}

type ArticleModel struct {
  ID    uint
  Title string
}

// UserCollectModel 用户收藏文章表
type UserCollectModel struct {
  UserID       uint         `gorm:"primaryKey"` // article_id
  UserModel    UserModel    `gorm:"foreignKey:UserID"`
  ArticleID    uint         `gorm:"primaryKey"` // tag_id
  ArticleModel ArticleModel `gorm:"foreignKey:ArticleID"`
  CreatedAt    time.Time
}

查询

var collects []UserCollectModel

var user UserModel
DB.Take(&user, "name = ?", "枫枫")
// 这里用map的原因是如果没查到,那就会查0值,如果是struct,则会忽略零值,全部查询
DB.Debug().Preload("UserModel").Preload("ArticleModel").Where(map[string]any{"user_id": user.ID}).Find(&collects)

for _, collect := range collects {
  fmt.Println(collect)
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java面向对象(进阶)-- 面向对象特征之三:多态性

文章目录 一、多态的形式和体现(1)为什么需要多态性(polymorphism)?(2) 对象的多态性 二、 多态的理解(1)如何理解多态性(2)Java中多态性的体现(3&#xff09…

VS c++多文件编译

前言:记录下我这个菜鸡学习的过程,如有错误恳请指出,不胜感激! 1.简单多文件编译调试 文件目录: 编译: -g选项是告诉编译器生成调试信息,这样可以在程序崩溃或出现错误时更容易地进行调试。这…

减轻关键基础设施网络安全风险的 3 种方法

物理安全和网络安全之间存在相当大的重叠,特别是在保护关键基础设施方面。防止基础设施被篡改需要在物理安全方面进行大量投资,但任何连接到互联网的设备都代表着更广泛网络的潜在攻击点。 缺乏足够保护的设备可能会给这些对手在网络中提供立足点&#…

张小泉的“老字号”快守不住了:限期整改,业绩和产品各有危机

撰稿|行星 来源|贝多财经 11月8日,商务部等5部门发布了中华老字号的复核结果。结果显示,全国有981家中华老字号企业通过了复核,73家中华老字号企业附条件通过复核,另有55家企业未能通过复核。 贝多财经发现,张小泉股…

【Python 千题 —— 基础篇】账号登录

题目描述 题目描述 简易登录系统。你的账号密码分别是 “student”,“123456”;请使用 if-else 设计一个简易登录系统,输入账号密码。登陆成功输出 “Welcome !”,登录失败输出 “Login failed !” 输入描述 输入账号和密码。…

Python环境安装、Pycharm开发工具安装(IDE)

Python下载 Python官网 Python安装 Python安装成功 Pycharm集成开发工具下载(IDE) PC集成开发工具 Pycharm集成开发工具安装(IDE) 安装完成 添加环境变量(前面勾选了Path不用配置) (1&…

电脑出现病毒提示解决办法

已检测:Trojan:Win32/WacatacA!ml 状态:已隔离 隔离的文件在不会损害设备的受限区域内。系统将自动删除它们 日期:2023/11/1013:21详细信息这个程序很危险,而且执行来自攻击者的命令 受影响的项目: driver: haStdnetfilter file: C:WINDOWSsystem32\drivers\haStdne…

keil和proteus联动要点

一、keil与proteus如何进行联动? 1.先安装vdmagdi.exe,这是驱动 2.要保证keil工程编译通过,左上角红色图标进行编译,黑色框图标进行链接。 3.生成hex文件 先点击这个图标 按照顺序点击,生成HEX文件。 4.在打开的prot…

思维模型 多看效应

本系列文章 主要是 分享 思维模型,涉及各个领域,重在提升认知。越熟悉,越喜欢。 1 多看效应的应用 1.1 多看效应在广告和营销领域的应用 1 可口可乐之歌 可口可乐公司在 20 世纪 60 年代推出了“可口可乐之歌”广告,这个广告通…

守护进程daemon(),C 库函数asctime、localtime,UDEV的配置文件,开机自启动,自动挂载U盘

一、守护进程 二、daemon()函数 三、C 库函数asctime、localtime 四、设置守护进程开机自启动 五、守护进程应用 编写判断守护进程是否在运行的程序 守护进程不让控制程序退出 把相关守护进程设置成开机自启动 六、dmesg 七、UDEV的配置文件(udev的rules编写&am…

jupyter notebook中markdown改变图像大小

文章目录 &#x1f56e;原始图像&#x1f56e;改变图像大小&#x1f56e;使图像靠左 在 jupyter notebook中&#xff0c;导入的图片过大&#xff0c;想要改变图像的大小 &#x1f56e;原始图像 &#x1f56e;改变图像大小 复制小括号里面的内容到src后面&#xff0c;满足<…

软件测试现状以及行业分析

大家都知道最近 ChatGPT 爆火&#xff0c;国外巨头争相宣布自己的相关计划&#xff0c;国内有点实力的企业也在亦步亦趋地跟进。不出意料的是&#xff0c;关于测试职业要被淘汰的话题又&#xff08;为什么要说又&#xff1f;&#xff09;在扎堆出现&#xff0c;内容跟之前还是大…

Leetcode—9.回文数【简单】

2023每日刷题&#xff08;二十六&#xff09; Leetcode—9.回文数 直接法实现代码 bool isPalindrome(int x) {int len 0;int arr[10] {0};int i 0;if(x < 0) {return false;}while(x) {arr[i] x % 10;x / 10;len; }for(i 0; i < len / 2; i) {if(arr[i] ! arr[le…

【LLM_03】自然语言处理基础_1

一、自然语言处理基基本任务和应用1、自然语言处理的基本任务2、搜索引擎的基本工作原理3、知识图谱的构建4、应用 二、词表示与语言模型1、词表示2、上下文3、语言模型4、神经网络在语言模型的应用 三、神经网络1、神经网络基本组成元素2、如何训练神经网络3、计算图的概念4、…

学习c#的第五天

目录 C# 运算符 算术运算符 关系运算符 逻辑运算符 位运算符 赋值运算符 其他运算符 C# 中的运算符优先级 C# 运算符 算术运算符 下表显示了 C# 支持的所有算术运算符。假设变量 A 的值为 10&#xff0c;变量 B 的值为 20&#xff0c;则&#xff1a; 运算符描述实例…

autollm 指令设计

autollm 指令设计 可循环示意图文本 示意图AI解释可循环示意图 文本 示意图 # <|aos|>环境<|bos|>他人<|cos|>自己<|dos|>表示是否进行写python 代码来从外界获取辅助数据来重构 前面所有的信息<|eos|>代表是否生成python 代码控制各种外审设备…

CCNA课程实验-13-PPPoE

目录 实验条件网络拓朴需求 配置实现基础配置模拟运营商ISP配置ISP的DNS配置出口路由器OR基础配置PC1基础配置 出口路由器OR配置PPPOE拨号创建NAT(PAT端口复用) PC1测试结果 实验条件 网络拓朴 需求 OR使用PPPoE的方式向ISP发送拨号的用户名和密码&#xff0c;用户名&#xf…

计算机视觉:使用opencv进行直线检测

1 直线检测介绍 在图像处理中&#xff0c;直线检测是一种常见的算法&#xff0c;它通常获取n个边缘点的集合&#xff0c;并找到通过这些边缘点的直线。其中用于直线检测&#xff0c;最为流行的检测器是基于霍夫变换的直线检测技术。 1.1 什么是霍夫变换 霍夫变换&#xff08…

GIS入门,xyz地图瓦片是什么,xyz数据格式详解,如何发布离线XYZ瓦片到nginx或者tomcat中

XYZ介绍 XYZ瓦片是一种在线地图数据格式,由goole公司开发。 与其他瓦片地图类似,XYZ瓦片将地图数据分解为一系列小的图像块,以提高地图显示效率和性能。 XYZ瓦片提供了一种开放的地图平台,使开发者可以轻松地将地图集成到自己的应用程序中。同时,它还提供了高分辨率图像和…

一篇文章真正讲懂模型评估指标(准确率,召回率,精确率,roc曲线,AUC值)

背景&#xff1a; 最近在做一些数据分析的比赛的时候遇到了一些头疼的问题&#xff0c;就是我们如何评估一个模型的好坏呢&#xff1f; 准确率&#xff0c;召回率&#xff0c;精确率&#xff0c;roc曲线&#xff0c;roc值等等&#xff0c;但是模型评估的时候用哪个指标呢&…