Gorm project practice-using gen and defining relationships between tables

gorm project practice

ER图

Image1

Relationship sorting

  1. One-to-one relationship:

    • User and UserLog: A user corresponds to a user log, through the primary key of the User model and the UserLog model Foreign keys establish one-to-one relationships.
  2. One-to-many relationship:

    • User and Teacher: A user can correspond to multiple teachers through the foreign key of the Teacher model (UserID ) to establish a one-to-many relationship with the primary key of the User model.
    • User and Student: A user can correspond to multiple students through the foreign key of the Student model (UserID ) to establish a one-to-many relationship with the primary key of the User model.
    • Teacher and Class: A teacher can have multiple classes through the foreign key of the Class model (TeacherID ) to establish a one-to-many relationship with the primary key of the Teacher model.
    • Student and StudentClass: A student can have multiple classes through the StudentClass foreign key of the model (StudentID ) to establish a one-to-many relationship with the primary key of the Student model.
    • Student and Attendance: A student can have multiple attendance records through the foreign key of the Attendance model (StudentID) Establish a one-to-many relationship with the primary key of the Student model.
  3. Many-to-many relationship:

    • Student and Class: A student can belong to multiple classes, and a class can have multiple students. The StudentClass model is used as an intermediate table to create Many-to-many relationship.
    • Teacher and Class: A teacher can teach multiple classes, and a class can have multiple teachers, through the foreign key of the Class model (< /span> the primary key of the model to establish a many-to-many relationship. TeacherID) and Teacher
  4. One-to-many reverse relationship:

    • Parent and Student: A parent can have multiple children through the foreign key of the Student model (StudentID ) to establish a one-to-many reverse relationship with the primary key of the Parent model.

Use gen to automatically generate code

First use the gen tool to generate code

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()
}

Define foreign key relationships in the model generated by gen

The generated model code is in dao/model

Image2

We need to define foreign key relationships in these Models. First define the relationships between the User table, Teacher table and Student table.

Image3

one-to-one relationship

First, determine the main table and supplementary table. The main table

  • Main table: User, gradually: UserID

  • Attached table: Student, foreign key: UserID

  • Attached table: Teacher, foreign key: UserID

  • Add two in model.User

Image4

  • Change generate, we need to use the changed model to generate query

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

Add user business logic

Here press UserType to create corresponding students and teachers.

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": "用户创建成功"})
}

Picture5

Delete user business logic

// 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)})
}

Image6

renew

Since this is the main table, logically just update the table and write the logic to change the corresponding table later.

Mainly to change the avatar and so on


Find

// 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})
}

Guess you like

Origin blog.csdn.net/qq_42901723/article/details/134354936