gorm之项目实战-使用gen以及定义表间关系

gorm之项目实战

ER图

Image1

关系整理

  1. 一对一关系:

    • User 和 UserLog: 一个用户对应一个用户日志,通过 User 模型的主键与 UserLog 模型的外键建立一对一关系。
  2. 一对多关系:

    • User 和 Teacher: 一个用户可以对应多个老师,通过 Teacher 模型的外键(UserID)与 User 模型的主键建立一对多关系。
    • User 和 Student: 一个用户可以对应多个学生,通过 Student 模型的外键(UserID)与 User 模型的主键建立一对多关系。
    • Teacher 和 Class: 一个老师可以有多个班级,通过 Class 模型的外键(TeacherID)与 Teacher 模型的主键建立一对多关系。
    • Student 和 StudentClass: 一个学生可以有多个班级,通过 StudentClass 模型的外键(StudentID)与 Student 模型的主键建立一对多关系。
    • Student 和 Attendance: 一个学生可以有多条考勤记录,通过 Attendance 模型的外键(StudentID)与 Student 模型的主键建立一对多关系。
  3. 多对多关系:

    • Student 和 Class: 一个学生可以属于多个班级,一个班级可以有多个学生,通过 StudentClass 模型作为中间表,建立多对多关系。
    • Teacher 和 Class: 一个老师可以教授多个班级,一个班级可以有多个老师,通过 Class 模型的外键(TeacherID)与 Teacher 模型的主键,建立多对多关系。
  4. 一对多逆向关系:

    • Parent 和 Student: 一个家长可以有多个子女,通过 Student 模型的外键(StudentID)与 Parent 模型的主键建立一对多逆向关系。

使用gen自动化生成代码

首先使用gen工具生成代码

package main// gorm gen configureimport ("fmt""gorm.io/driver/mysql""gorm.io/gorm""gorm.io/gen"
)const MySQLDSN = "root:root@tcp(127.0.0.1:3306)/school?charset=utf8mb4&parseTime=True"func connectDB(dsn string) *gorm.DB {db, err := gorm.Open(mysql.Open(dsn))if err != nil {panic(fmt.Errorf("connect db fail: %w", err))}return db
}func main() {// 指定生成代码的具体相对目录(相对当前文件),默认为:./query// 默认生成需要使用WithContext之后才可以查询的代码,但可以通过设置gen.WithoutContext禁用该模式g := gen.NewGenerator(gen.Config{// 默认会在 OutPath 目录生成CRUD代码,并且同目录下生成 model 包// 所以OutPath最终package不能设置为model,在有数据库表同步的情况下会产生冲突// 若一定要使用可以通过ModelPkgPath单独指定model package的名称OutPath: "dao/query",/* ModelPkgPath: "dal/model"*/// gen.WithoutContext:禁用WithContext模式// gen.WithDefaultQuery:生成一个全局Query对象Q// gen.WithQueryInterface:生成Query接口Mode: gen.WithDefaultQuery | gen.WithQueryInterface,})// 通常复用项目中已有的SQL连接配置db(*gorm.DB)// 非必需,但如果需要复用连接时的gorm.Config或需要连接数据库同步表信息则必须设置g.UseDB(connectDB(MySQLDSN))// 从连接的数据库为所有表生成Model结构体和CRUD代码// 也可以手动指定需要生成代码的数据表g.ApplyBasic(g.GenerateAllTable()...)// 执行并生成代码g.Execute()
}

在gen生成的model中定义外键联系

生成的model代码在dao/model

Image2

我们需要在这些Model中定义外键关系,先把User表and Teacher表与Student表关系定义

Image3

一对一关系

首先先确定主表和附表,主表

  • 主表:User,逐渐:UserID

  • 附表:Student,外键:UserID

  • 附表:Teacher,外键:UserID

  • 在model.User中添加两个

Image4

  • 把generate改下,我们要用改过的模型生成query

  •     g.ApplyBasic(model.Student{},model.Teacher{},model.User{},model.UserLog{},model.Class{},model.Course{},model.Attendance{},model.StudentClass{},model.Parent{},)// 执行并生成代码g.Execute()
    

增加用户业务逻辑

这边按UserType新建对应的学生和教师

func CreateUser(c *gin.Context) {var req request.CreateUserRequestif err := c.ShouldBindJSON(&req); err != nil {c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "error": "创建用户请求失败,无效的请求参数"})return}var user model.Userswitch req.UserType {case "Student":user = model.User{Username:  req.Username,Password:  req.Password,OpenID:    req.OpenID,Avatar:    req.Avatar,LastLogin: time.Now(),UserType:  req.UserType,IsValid:   req.IsValid,Student: model.Student{StudentName: req.Username,},}case "Teacher":user = model.User{Username:  req.Username,Password:  req.Password,OpenID:    req.OpenID,Avatar:    req.Avatar,LastLogin: time.Now(),UserType:  req.UserType,IsValid:   req.IsValid,Teacher: model.Teacher{TeacherName: req.Username,},}default:c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "error": "无效的用户类型"})return}err := query.User.WithContext(context.Background()).Create(&user)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"code": http.StatusInternalServerError, "error": fmt.Sprintf("创建用户请求失败,无法创建用户: %v", err)})return}c.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "message": "用户创建成功"})
}

Image5

删除用户业务逻辑

// DeleteUser 处理删除用户请求的函数
func DeleteUser(c *gin.Context) {userIDStr := c.Param("id") // Assuming the route has "id" parametervar User model.UseruserID, err := strconv.ParseInt(userIDStr, 10, 64)if err != nil {c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "error": "Failed to delete user, invalid user ID"})return}//var user model.Userconfig.GVA_DB.Take(&User, userID)ret := config.GVA_DB.Select("Student").Delete(&User)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"code": http.StatusInternalServerError, "error": fmt.Sprintf("Failed to delete user, unable to delete user: %v", err)})return}c.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "message": fmt.Sprintf("User deleted successfully, RowsAffected: %v", ret.RowsAffected)})
}

Image6

更新

这里因为是主表,逻辑上之更新注表就好,后面改相应表的在编写逻辑

主要是改改头像什么的


查找

// GetUser 处理获取单个用户请求的函数
func GetUser(c *gin.Context) {userIDStr := c.Param("id") // Assuming the route has "id" parameteru := query.UseruserID, err := strconv.ParseInt(userIDStr, 10, 64)if err != nil {c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "error": "Failed to get user, invalid user ID"})return}user, err := query.User.WithContext(context.Background()).Where(query.User.UserID.Eq(int32(userID))).Preload(u.Student, u.Teacher).First()if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"code": http.StatusInternalServerError, "error": fmt.Sprintf("Failed to get user, unable to get user: %v", err)})return}c.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "user": user})
}// GetAllUsers 处理获取所有用户请求的函数
func GetAllUsers(c *gin.Context) {u := query.Userusers, err := query.User.WithContext(context.Background()).Preload(u.Student, u.Teacher).Find()if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"code": http.StatusInternalServerError, "error": fmt.Sprintf("Failed to get all users, unable to get user list: %v", err)})return}c.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "users": users})
}

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

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

相关文章

Android——Gradle插件gradle-wrapper.properties

一、Android Studio版本,Android Gradle插件版本,Gradle版本 Android Studio 通过Android Gradle插件 使用 Gradle来构建代码; Android Studio每次升级后, Android Gradle 插件自动更新,对应的Gradle版本也会变动&…

openssl研发之base64编解码实例

一、base64编码介绍 Base64编码是一种将二进制数据转换成ASCII字符的编码方式。它主要用于在文本协议中传输二进制数据,例如电子邮件的附件、XML文档、JSON数据等。 Base64编码的特点如下: 字符集: Base64编码使用64个字符来表示二进制数据…

C#中的扩展方法---Extension

C#中扩展方法是C# 3.0/.NET 3.x 新增特性,能够实现向现有类型中“添加”方法,以下主要介绍C#中扩展方法的声明及使用。 1、扩展方法的声明 扩展方法使能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型…

xlua游戏热更新(C#访问lua)

xlua作为Unity资源热更新的重要解决方案api,在Tecent重多游戏中被采用,本文通过案例去讲解xlua代码结构层次。 /** Tencent is pleased to support the open source community by making xLua available.* Copyright (C) 2016 THL A29 Limited, a Tence…

快速走进通信世界 --- 基础知识扫盲

想不到吧,家人们,博主好久没来更新文章了,而且这次更新的是关于通信工程的文章。博主确实以前一直更新关于编程的文章,只不过最近在学习一些新的知识,以后有机会了我还是会继续更新一些编程技术文章的。不过每一门技术…

基于单片机设计的智能风扇(红外线无线控制开关调速定时)

一、项目介绍 在炎热的夏季,风扇成为人们室内生活中必不可少的电器产品。然而,传统的风扇控制方式存在一些不便之处,比如需要手动操作开关、无法远程控制和调速,以及缺乏定时功能等。为了解决这些问题,设计了一款基于…

如何用java写一个网站:从零搭建个性化网站

随着互联网的迅猛发展,Java作为一种强大而灵活的编程语言,为构建各类网站提供了丰富的解决方案。本文将探讨如何使用Java编写一个个性化网站,并通过具体实例进行深入分析。 第一步:选择适当的技术栈 在着手构建网站之前&#xff0…

【代码随想录】算法训练计划18

1、513. 找树左下角的值 题目: 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 思路: 递归,规则,基本可以自己写出来 var maxDepth int var res int fun…

深度学习之基于Django+Tensorflow商品识别管理系统

欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 项目简介 本系统是一个基于DjangoTensorflow的商品识别管理系统。通过深度学习技术,实现商品的自动识别…

Linux系统编程——文件的打开及创建

打开(open) 使用open函数需要包含以下三个头文件&#xff1a; #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> open的函数定义格式 int open(const char *pathname,int flags); int open(const char *pathname,int flags,mode_t mode…

CKA认证模块②-K8S企业运维和落地实战

CKA认证模块②-K8S企业运维和落地实战 Pod高级实战-Pod生命周期-启动钩子,停止钩子 Pod生命周期完整流程介绍 容器钩子; 容器探测; Pod重启策略; Pod的终止过程; Init容器; 初始化容器最佳实践 初始化容器与主容器区别是? init容器没有readinessProbe… [rootk8s-mast…

【机器学习】七、降维与度量学习

1. 维数灾难 样本的特征数称为维数&#xff08;dimensionality&#xff09;&#xff0c;当维数非常大时&#xff0c;也就是现在所说的维数灾难。 维数灾难具体表现在&#xff1a;在高维情形下&#xff0c;数据样本将变得十分稀疏&#xff0c;因为此时要满足训练样本为“密采样…