一对一关系:
User
模型的主键与 UserLog
模型的外键建立一对一关系。一对多关系:
Teacher
模型的外键(UserID
)与 User
模型的主键建立一对多关系。Student
模型的外键(UserID
)与 User
模型的主键建立一对多关系。Class
模型的外键(TeacherID
)与 Teacher
模型的主键建立一对多关系。StudentClass
模型的外键(StudentID
)与 Student
模型的主键建立一对多关系。Attendance
模型的外键(StudentID
)与 Student
模型的主键建立一对多关系。多对多关系:
StudentClass
模型作为中间表,建立多对多关系。Class
模型的外键(TeacherID
)与 Teacher
模型的主键,建立多对多关系。一对多逆向关系:
Student
模型的外键(StudentID
)与 Parent
模型的主键建立一对多逆向关系。首先使用gen工具生成代码
package main
// gorm gen configure
import (
"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()
}
生成的model代码在dao/model
我们需要在这些Model中定义外键关系,先把User表and Teacher表与Student表关系定义
首先先确定主表和附表,主表
主表:User,逐渐:UserID
附表:Student,外键:UserID
附表:Teacher,外键:UserID
在model.User中添加两个
把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.CreateUserRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": http.StatusBadRequest, "error": "创建用户请求失败,无效的请求参数"})
return
}
var user model.User
switch 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": "用户创建成功"})
}
// DeleteUser 处理删除用户请求的函数
func DeleteUser(c *gin.Context) {
userIDStr := c.Param("id") // Assuming the route has "id" parameter
var User model.User
userID, 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.User
config.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)})
}
这里因为是主表,逻辑上之更新注表就好,后面改相应表的在编写逻辑
主要是改改头像什么的
// GetUser 处理获取单个用户请求的函数
func GetUser(c *gin.Context) {
userIDStr := c.Param("id") // Assuming the route has "id" parameter
u := query.User
userID, 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.User
users, 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})
}