Golang gorm

news2024/11/15 6:54:42

GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.

一 对多入门


比如要开发cmdb的系统,无论是硬件还是软件。硬件对应的就是对应的哪个开发在用。或者服务对应的是哪个业务模块在使用,或者应用谁在使用。那么这就是一对多的关系。

has many介绍

  • has many 关联就是创建和另一个模型的一对多关系(数据库里面是一对多,然后struct里面也是一对多)
  • 例如, 例如每一个用户都拥有多张信用卡,这样就是生活中一个简单的一对多关系

在设计表的时候不可能将所有的信息都放在一个表里面,那么表就会非常非常的宽。这样字段就会非常的多,性能就会受到影响。

在设计的时候这里其实就可以设置为两张表。一个是用户的详情表和信用卡的详情表,用户表里面加上卡的id和他做一个关联,那么这就是一对多的关系。

当一个数据库存储了很多数据的时候就需要分库分表,上面也类似,将一张表分为两张表。

creditcar的外键是userid。

package main

import (
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)


type User struct {
	gorm.Model  //默认创建三个时间字段和一个id字段,create_at update_at delete_at这样可以知道创建时间/更新时间/删除时间
	CreditCards []*CreditCard66
}


//用户有多张信用卡,UserID是外键
type CreditCard struct {
	gorm.Model
	Number   string
	UserId int //默认会在CreditCard表中生成User66Id字段作为与user表关联的外键id
  //默认会在CreditCard表中生成UserID字段作为与User表关联的外键ID 
}

func main() {
	dsn := "root:7PXjAkY!&nlR@tcp(192.168.11.128:3306)/test_db?charset=utf8mb4&parseTime=True&loc=Local"
	db, _ := gorm.Open(mysql.Open(dsn66), &gorm.Config{})
	db.AutoMigrate(User{}, CreditCard{})
}
mysql> show tables;
+-------------------+
| Tables_in_test_db |
+-------------------+
| credit_cards      |
| users             |
+-------------------+
2 rows in set (0.00 sec)

mysql> desc users;
+------------+-----------------+------+-----+---------+----------------+
| Field      | Type            | Null | Key | Default | Extra          |
+------------+-----------------+------+-----+---------+----------------+
| id         | bigint unsigned | NO   | PRI | NULL    | auto_increment |
| created_at | datetime(3)     | YES  |     | NULL    |                |
| updated_at | datetime(3)     | YES  |     | NULL    |                |
| deleted_at | datetime(3)     | YES  | MUL | NULL    |                |
+------------+-----------------+------+-----+---------+----------------+

mysql> desc credit_cards;
+------------+-----------------+------+-----+---------+----------------+
| Field      | Type            | Null | Key | Default | Extra          |
+------------+-----------------+------+-----+---------+----------------+
| id         | bigint unsigned | NO   | PRI | NULL    | auto_increment |
| created_at | datetime(3)     | YES  |     | NULL    |                |
| updated_at | datetime(3)     | YES  |     | NULL    |                |
| deleted_at | datetime(3)     | YES  | MUL | NULL    |                |
| number     | bigint          | YES  |     | NULL    |                |
| user_id    | bigint unsigned | YES  | MUL | NULL    |                |
+------------+-----------------+------+-----+---------+----------------+

mysql> drop table users;
ERROR 3730 (HY000): Cannot drop table 'users' referenced by a foreign key constraint 'fk_users_credit_cards' on table 'credit_cards'.

 二  外键


为了定义一对多关系,外键是必须存在的,默认外键的名字是所有者类型的名字加上它的主键
(UserId) 。 就像上面的例子,为了定义一个属于User 的模型,外键就应该为 UserID
使用其他的字段名作为外键,你可以通过 foreignkey 来定制它,例如 :
type User struct{
 gorm.Model
 CreditCards []CreditCard `gorm:"foreignKey:UserRefer"`
}

type CreditCard struct{
 gorm.Model
 Number  string
 UserRefer uint
}

`gorm:"foreignKey:UserRefer"` 可以使用这个字段来去改它的外键。

import (
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	CreditCards []*CreditCard `gorm:"foreignKey:UserRefer"`
}

type CreditCard struct {
	gorm.Model
	Number    int
	UserRefer int  
}

func main() {
	dsn6 := "root:7PXjAkY!&nlR@tcp(192.168.11.128:3306)/test_db?charset=utf8mb4&parseTime=True&loc=Local"
	db, _ := gorm.Open(mysql.Open(dsn6), &gorm.Config{})
	db.AutoMigrate(&User{}, &CreditCard{})
}

mysql> desc users;
+------------+-----------------+------+-----+---------+----------------+
| Field      | Type            | Null | Key | Default | Extra          |
+------------+-----------------+------+-----+---------+----------------+
| id         | bigint unsigned | NO   | PRI | NULL    | auto_increment |
| created_at | datetime(3)     | YES  |     | NULL    |                |
| updated_at | datetime(3)     | YES  |     | NULL    |                |
| deleted_at | datetime(3)     | YES  | MUL | NULL    |                |
+------------+-----------------+------+-----+---------+----------------+

mysql> desc credit_cards;
+------------+-----------------+------+-----+---------+----------------+
| Field      | Type            | Null | Key | Default | Extra          |
+------------+-----------------+------+-----+---------+----------------+
| id         | bigint unsigned | NO   | PRI | NULL    | auto_increment |
| created_at | datetime(3)     | YES  |     | NULL    |                |
| updated_at | datetime(3)     | YES  |     | NULL    |                |
| deleted_at | datetime(3)     | YES  | MUL | NULL    |                |
| number     | bigint          | YES  |     | NULL    |                |
| user_refer | bigint unsigned | YES  | MUL | NULL    |                |
+------------+-----------------+------+-----+---------+----------------+

mysql> drop tables users;
ERROR 3730 (HY000): Cannot drop table 'users' referenced by a foreign key constraint 'fk_users_credit_cards' on table 'credit_cards'.

一般不推荐使用这种方式,还是推荐使用Userid的方式。

三 外键关联


GORM 通常使用所有者的主键作为外键的值,在上面的例子中,它就是 User ID 。当你分配信用卡给一个用户,GORM 将保存用户 ID 到信用卡表的 UserID 字段中。 你能通过association_foreignkey来改变它。
type User struct {
    gorm.Model
    MemberNumber string
// 默认CreditCard会使用User表的Id作为外键,association_foreignkey:MemberNumber
// 指定使用MemberNumber 作为外键关联
CreditCards []CreditCard
`gorm:"foreignkey:UserMemberNumber;association_foreignkey:MemberNumber"`
}


type CreditCard struct {
    gorm.Model
    Number string
    UserMemberNumber string
}

其实就是creditcard外键UserMemberNumber直接去找user的 MemberNumber。

上面其实也就是改变了外键的默认值,默认外键是Userid,那么现在变为了MemberNumber。

一般使用默认id的外键就能够覆盖很多场景,上面这种只是举例。

package main

import (
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	MemberNumber string
	CreditCards  []*CreditCard `gorm:"foreignKey:UserMemberNumber;association_foreignKey:MemberNumber"`
}

type CreditCard struct {
	gorm.Model
	Number           int
	UserMemberNumber string
}

func main() {
	dsn6 := "root:7PXjAkY!&nlR@tcp(192.168.11.128:3306)/test_db?charset=utf8mb4&parseTime=True&loc=Local"
	db, _ := gorm.Open(mysql.Open(dsn6), &gorm.Config{})
	db.AutoMigrate(&User{}, &CreditCard{})
}


mysql> desc users;
+---------------+-----------------+------+-----+---------+----------------+
| Field         | Type            | Null | Key | Default | Extra          |
+---------------+-----------------+------+-----+---------+----------------+
| id            | bigint unsigned | NO   | PRI | NULL    | auto_increment |
| created_at    | datetime(3)     | YES  |     | NULL    |                |
| updated_at    | datetime(3)     | YES  |     | NULL    |                |
| deleted_at    | datetime(3)     | YES  | MUL | NULL    |                |
| member_number | longtext        | YES  |     | NULL    |                |
+---------------+-----------------+------+-----+---------+----------------+

mysql> desc credit_cards;
+--------------------+-----------------+------+-----+---------+----------------+
| Field              | Type            | Null | Key | Default | Extra          |
+--------------------+-----------------+------+-----+---------+----------------+
| id                 | bigint unsigned | NO   | PRI | NULL    | auto_increment |
| created_at         | datetime(3)     | YES  |     | NULL    |                |
| updated_at         | datetime(3)     | YES  |     | NULL    |                |
| deleted_at         | datetime(3)     | YES  | MUL | NULL    |                |
| number             | bigint          | YES  |     | NULL    |                |
| user_member_number | bigint unsigned | YES  | MUL | NULL    |                |
+--------------------+-----------------+------+-----+---------+----------------+

四 创建一对多表


1. 表结构定义
/*
constraint:OnUpdate:CASCADE 【当User表更新,也会同步给CreditCards】 // 外键约束
OnDelete:SET NULL 【当User中数据被删除时,CreditCard关联设置为 NULL,不删除记录】
*/

type User struct {
    gorm.Model
    Username string `json:"username" gorm:"column:username"`
    CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}

type CreditCard struct {
    gorm.Model
    Number string
    UserID uint
}

func main() {
    // 0、连接数据库
    dsn := "root:1@tcp(127.0.0.1:3306)/test_db?
    charset=utf8mb4&parseTime=True&loc=Local"
    db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})

// 创建表结构
    db.AutoMigrate(User{}, CreditCard{})

// 1、创建一对多
    user := User{
        Username: "zhangsan",
        CreditCards: []CreditCard{
        {Number: "0001"},
        {Number: "0002"},
    },
}

db.Create(&user)

// 2、为已存在用户添加信用卡
    u := User{Username: "zhangsan"}
    db.First(&u)
    //fmt.Println(u.Username)

}
上面如果要查询的话是没有去做关联查询的,只能查到user表相关的信息,并不能查到creditcard信息。
2. 创建结果说明
我们没有指定 foreignkey ,所以会与 UserID 字段自动建立外键关联关系

3. 一对多Association 查找关联 使用 Association 方法, 需要把把 User 查询好, 然后根据 User 定义中指定的 AssociationForeignKey 去查找 CreditCard

import (
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	UserName    string       `json:"username" gorm:"column:username"`
	CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}

type CreditCard struct {
	gorm.Model
	Number string
	UserID int
}

func main() {
	dsn6 := "root:7PXjAkY!&nlR@tcp(192.168.11.128:3306)/test_db?charset=utf8mb4&parseTime=True&loc=Local"
	db, _ := gorm.Open(mysql.Open(dsn6), &gorm.Config{})
	db.AutoMigrate(&User{}, &CreditCard{})

	/*
		u := &User{
			Model:    gorm.Model{},
			UserName: "lucas",
			CreditCards: []*CreditCard{
				{Number: "0001", UserID: 1},
				{Number: "0002", UserID: 2},
			},
		}

		db.Create(u)

	*/

    // 1、查找 用户名为 lucas 的所有信用卡信息
	u1 := &User{UserName: "lucas"}

    // Association必须要先查出User才能关联查询对应的CreditCard
	db.First(u1)

	db.Model(u1).Association("CreditCards").Find(&u1.CreditCards)
	fmt.Println(u1)

}

追加

package main

import (
	"encoding/json"
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	UserName    string       `json:"username" gorm:"column:username"`
	CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}

type CreditCard struct {
	gorm.Model
	Number string
	UserID int
}

func main() {
	dsn6 := "root:7PXjAkY!&nlR@tcp(192.168.11.128:3306)/test_db?charset=utf8mb4&parseTime=True&loc=Local"
	db, _ := gorm.Open(mysql.Open(dsn6), &gorm.Config{})
	db.AutoMigrate(&User{}, &CreditCard{})

	u := &User{
		Model:    gorm.Model{},
		UserName: "lucas",
		CreditCards: []CreditCard{
			{Number: "0001", UserID: 0},
			{Number: "0002", UserID: 1},
		},
	}

	db.Create(u)

	u1 := &User{UserName: "lucas"}
	db.First(u1)
	
	db.Model(u1).Association("CreditCards").Find(&u1.CreditCards)
	fmt.Println(u1)

	db.Model(u1).Association("CreditCards").Append([]CreditCard{
		{Number: "0008", UserID: 1},
	})
	fmt.Println(u1)

	strUser, _ := json.Marshal(u1)
	fmt.Println(string(strUser))
}


&{{1 2023-04-16 10:48:54.423 +0800 CST 2023-04-16 14:12:45.825 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} lucas []}

&{{1 2023-04-16 10:48:54.423 +0800 CST 2023-04-16 14:15:51.44 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} lucas [{{17 2023-04-16 14:15:51.445
 +0800 CST 2023-04-16 14:15:51.445 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} 0008 1}]}

{"ID":1,"CreatedAt":"2023-04-16T10:48:54.423+08:00","UpdatedAt":"2023-04-16T14:15:51.44+08:00","DeletedAt":null,"username":"lucas","CreditCards":[
{"ID":17,"CreatedAt":"2023-04-16T14:15:51.445+08:00","UpdatedAt":"2023-04-16T14:15:51.445+08:00","DeletedAt":null,"Number":"0008","UserID":1}]} 

 

 

4. 一对多Preload 预加载

使用 Preload 方法, 在查询 User 时先去获取 CreditCard 的记录

和上面associate不一样,他们两个最大的区别是执行的顺序是不一样的,associate是先去获取user,再去获取creditcard。

preload是先去获取creditcard,再去获取user。

package main
import (
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
/*
constraint:OnUpdate:CASCADE 【当User表更新,也会同步给CreditCards】
OnDelete:SET NULL 【当User中数据被删除时,CreditCard关联设置为 NULL,不删除记录】
*/
type User struct {
gorm.Model
Username string `json:"username" gorm:"column:username"`
CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET
NULL;"`
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
func main() {
// 0、连接数据库
dsn := "root:1@tcp(127.0.0.1:3306)/test_db?
charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 1、预加载: 查找 user 时预加载相关 CreditCards
//users := User{Username: "zhangsan"} // 只查找张三用户的信用卡信息
users := []User{}
db.Preload("CreditCards").Find(&users)
查询结果


[
{
"ID":1,
"username":"zhangsan",
"CreditCards":[
{
"ID":1,
"Number":"0001",
"UserID":1
},
...
]
}
]

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

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

相关文章

【CXL】在gem5中跑一个实际的应用程序——Viper KV存储

有了CXL扩展内存,自然是要在DRAMCXL扩展内存上跑跑实际的应用程序,看看和DRAM传统磁盘有什么区别。 实际的应用程序其实就是一些工业界部署使用的,比如数据库、深度学习训练项目等等。本文主要找到一个KV存储Viper,搭建并进行简单…

水电设计院信息管理系统1.0

水电设计公司信息管理系统软件使用说明书 代码太多就不贴了,请在我的资源里下载,已部署在企业进行试运行。https://download.csdn.net/download/weixin_44735475/87704302 目录 1.引言 1 2.项目背景 1 3.系统功能 2 3.1系统功能 2 3.2系统性能 2 3.3系…

Python GUI自动化神器pyautogui,精准识别图片并自动点赞(32)

小朋友们好,大朋友们好! 我是猫妹,一名爱上Python编程的小学生。 欢迎和猫妹一起,趣味学Python。 今日主题 你听过GUI自动化吗? GUI自动化就是用软件模拟鼠标和键盘的操作。 提到Python GUI自动化,不…

Flink State 笔记帖

1 State 分类 Operator State 主要用在Source、Sink等没有key分布的位置。 Keyed State 用在keyBy后的KeyedStream里,每个存储状态与一个key想关联。 ValueState ListState MapState ReducingState AggeratingState 2 State Backend StateBackend分类 HashMa…

JVM之JDK 监控和故障处理工具总结

JDK 命令行工具 这些命令在 JDK 安装目录下的 bin 目录下: jps (JVM Process Status): 类似 UNIX 的 ps 命令。用于查看所有 Java 进程的启动类、传入参数和Java 虚拟机参数等信息;jstat(JVM Statistics Monitoring Tool&#x…

虚拟人与娱乐传媒融合,推动综艺新模式

经过多年的更新迭代和市场的推动,虚拟人技术正在逐渐迈向成熟:3D虚拟形象的制作变得越来越精致且真实,并且出现了越来越多功能丰富使用便捷的动捕设备。因此,包括综艺影视在内的诸多领域,开始尝试将虚拟人技术融入行业…

DETR:end-to-end object detection with transformers

DETR 论文精读【论文精读】_哔哩哔哩_bilibili更多论文:https://github.com/mli/paper-reading/, 视频播放量 90699、弹幕量 493、点赞数 3566、投硬币枚数 2939、收藏人数 2564、转发人数 663, 视频作者 跟李沐学AI, 作者简介 ,相关视频:在线…

【设计原则】依赖倒置原则--高层代码和底层代码到底谁该依赖谁?

文章目录 前言一、谁依赖谁二、依赖于抽象总结 前言 依赖这个词,程序员们都好理解,意思就是,我这段代码用到了谁,我就依赖了谁。依赖容易有,但能不能把依赖弄对,就需要动点脑子了。 如果依赖关系没有处理…

【红队APT】反朔源隐藏C2项目CDN域前置云函数数据中转DNS转发

文章目录 域前置-CDN隐藏C2真实IP 防止被溯源什么是域前置条件原理 完整复现域前置溯源 DNS协议-域名记录解析云函数-腾讯云操作云函数如何溯源 端口转发-Iptables中间件反向代理-Apache 域前置-CDN隐藏C2真实IP 防止被溯源 国内外云服务上大部分已经不支持域前置了&#xff0…

局域网哪些特点?快解析内网穿透实现外网访问局域网SVN

无线局域网传统是有线局域网络的补充和扩展,具有灵活性、可移动性及较低的投资成本等优势,受到了家庭网络用户、中小型办公室用户、广大企业用户及电信运营商的青睐,成为当前整个数据通信领域发展最快的产业之一。 局域网一般为一个单位所建&…

(20230418 SALE算法)个人模型学习笔记记录 500

写给自己: 一、先不做对称的结构试一下,上一个ALE的模型,记得有次没有做对称结构,居然需要11天才能算完,当时吓得我赶紧删除了,做了对称结构。先试一下这个S-ALE能否不做成对称的。但是我感觉或许也会计算很长时间。要不我先试一下。 写给自己: 一、先不做对称的结构…

【UE 控件蓝图】通过键盘选中要点击的按钮 通过Enter键点击

上一篇【UE 控件蓝图】菜单及功能实现博客已经完成了菜单的制作,但是我们只能通过鼠标来点击菜单选项,本篇博客实现的是能够通过键盘的上下键来选中按钮,然后按下“Enter”键来实现点击按钮的效果。 效果 可以看到并没有移动鼠标也可以通过…

Node【Global全局对象】之【Console】

文章目录 🌟前言🌟Console模块🌟console对象方法🌟console.log()🌟console.dir()🌟console.time()🌟console.assert()🌟console.trace()🌟写在最后 🌟前言 哈…

升级数智化底座领先实践:北京地铁加速财务数智化转型

近年来,数字经济蓬勃发展,正在成为重组全球要素资源、重塑全球经济结构、改变全球竞争格局的关键力量。中共中央、国务院印发的《数字中国建设整体布局规划》再次明确指出,做强做优做大数字经济。推动数字技术和实体经济深度融合,…

如何使用Postman做多接口测试【实战】

1. 摘要 本文讲解使用postman做接口测试和批量接口测试的方法。 2.实践内容 2.1 环境变量和全局变量的设置: a. 环境变量的设置方法如下图。点击设置一个环境变量,名为"user_pwd", 里面设置username 和passwd的值,然后在请求中…

gdb切换窗口焦点

为了辅助调试,一般会使用layout src,调起TUI显示代码: 然而这种情况下我们写命令很不方便,无法方便地使用上一条命令、退格等。 按动上下左右方向键盘只会移动代码框,然而在伪终端下,可以用鼠标滚轮来上下…

同步TMS-fMRI研究脑功能网络的指南

导读 经颅磁刺激(TMS)可直接激活人脑新皮层中的神经元,并已被证明是认知神经科学因果假设检验的基础。通过同时使用TMS和fMRI,皮层TMS对远端皮层和皮层下结构活动的影响可以通过改变TMS输出强度来量化。然而,TMS在fMRI时间序列中产生了显著的…

Google Earth Engine谷歌地球引擎GEE合并多个不同Asset的方法

本文介绍在GEE中,将多个存储有点要素的Asset加以合并,使得其成为一个Asset的方法。 本文是谷歌地球引擎(Google Earth Engine,GEE)系列教学文章的第十五篇,更多GEE文章请参考专栏:GEE学习与应用…

银行数字化转型导师坚鹏:商业银行数字化风控(2天)

商业银行数字化风控 课程背景: 数字化背景下,很多银行存在以下问题: 不清楚商业银行数字化风控发展现状? 不清楚对公业务数字化风控工作如何开展? 不知道零售业务数字化风控工作如何开展? 课程特色…

web攻防-通用漏洞验证码识别复用调用找回密码重定向状态值

目录 一、知识点概述 二、找回密码过程中涉及到的安全问题 三、案例演示 <验证码回显> <修改Response状态值> <验证码爆破> 四、真实案例1 <更改状态值> <验证码接口调用> 五、真实案例2 <用户名重定向> 六、安全修复方案 一、…