Last active
February 3, 2024 13:20
-
-
Save wangrenjun/48f03d2980c8f953f1e9ca5d7e09de5c to your computer and use it in GitHub Desktop.
Example of GORM using join
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
"time" | |
"gorm.io/driver/postgres" | |
"gorm.io/gorm" | |
) | |
var dsn = "host=127.0.0.1 user=postgres dbname=gormexample port=5432 sslmode=disable password=XXX" | |
func main() { | |
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{}) | |
if err != nil { | |
panic(err) | |
} | |
sqldb, err := db.DB() | |
if err != nil { | |
panic(err) | |
} | |
sqldb.SetMaxIdleConns(10) // 设置连接池中空闲连接的最大数量 | |
sqldb.SetMaxOpenConns(100) // 设置打开数据库连接的最大数量 | |
sqldb.SetConnMaxLifetime(time.Second * 30) // 设置连接可复用的最大时间 | |
AutoMigrate(db) | |
CreateSchools(db) | |
CreateClasses(db) | |
CreateStudents(db) | |
listAllStudentInfo(db) | |
listAllStudentInfoUnderGrade(db, 4) | |
} | |
func AutoMigrate(db *gorm.DB) { | |
db.AutoMigrate(&Student{}) | |
db.AutoMigrate(&Class{}) | |
db.AutoMigrate(&School{}) | |
} | |
func CreateSchools(db *gorm.DB) { | |
schools := []School{ | |
{ | |
Name: "SCHOOL.NAME.1", | |
Address: "SCHOOL.ADDRESS.1", | |
}, | |
{ | |
Name: "SCHOOL.NAME.2", | |
Address: "SCHOOL.ADDRESS.2", | |
}, | |
{ | |
Name: "SCHOOL.NAME.3", | |
Address: "SCHOOL.ADDRESS.3", | |
}, | |
} | |
res := db.Create(&schools) | |
if res.Error != nil { | |
panic(res.Error) | |
} | |
for _, school := range schools { | |
fmt.Printf("school.ID: %d\n", school.ID) | |
} | |
} | |
func CreateClasses(db *gorm.DB) { | |
classes := []Class{ | |
{ | |
Grade: 1, | |
Class: 1, | |
SchoolId: 1, | |
Address: "CLASS.ADDRESS.1.1.1", | |
}, | |
{ | |
Grade: 1, | |
Class: 2, | |
SchoolId: 1, | |
Address: "CLASS.ADDRESS.1.2.1", | |
}, | |
{ | |
Grade: 2, | |
Class: 1, | |
SchoolId: 1, | |
Address: "CLASS.ADDRESS.2.1.1", | |
}, | |
{ | |
Grade: 2, | |
Class: 2, | |
SchoolId: 1, | |
Address: "CLASS.ADDRESS.2.2.1", | |
}, | |
{ | |
Grade: 4, | |
Class: 5, | |
SchoolId: 3, | |
Address: "CLASS.ADDRESS.4.5.3", | |
}, | |
} | |
res := db.Create(&classes) | |
if res.Error != nil { | |
panic(res.Error) | |
} | |
for _, class := range classes { | |
fmt.Printf("class.ID: %d\n", class.ID) | |
} | |
} | |
func CreateStudents(db *gorm.DB) { | |
students := []Student{ | |
{ | |
SchoolId: 1, | |
Grade: 1, | |
Class: 1, | |
Name: "STUDENT.AAA", | |
}, | |
{ | |
SchoolId: 1, | |
Grade: 1, | |
Class: 1, | |
Name: "STUDENT.BBB", | |
}, | |
{ | |
SchoolId: 1, | |
Grade: 1, | |
Class: 2, | |
Name: "STUDENT.CCC", | |
}, | |
{ | |
SchoolId: 1, | |
Grade: 1, | |
Class: 2, | |
Name: "STUDENT.DDD", | |
}, | |
{ | |
SchoolId: 3, | |
Grade: 4, | |
Class: 5, | |
Name: "STUDENT.EEE", | |
}, | |
} | |
res := db.Create(&students) | |
if res.Error != nil { | |
panic(res.Error) | |
} | |
for _, student := range students { | |
fmt.Printf("student.ID: %d\n", student.ID) | |
} | |
} | |
type StudentInfo struct { | |
Student `gorm:"embedded;embeddedPrefix:student_"` | |
Class `gorm:"embedded;embeddedPrefix:class_"` | |
School `gorm:"embedded;embeddedPrefix:school_"` | |
} | |
// select students.id, students.created_at, students.updated_at, students.grade, | |
// students.class, students.name, classes.address, schools.name, schools.address | |
// from (students inner join classes on students.class_id = classes.id) | |
// inner join schools on classes.school_id = schools.id | |
func listAllStudentInfo(db *gorm.DB) { | |
var results []StudentInfo | |
fields := ` | |
students.id AS student_id, | |
students.created_at AS student_created_at, | |
students.updated_at AS student_updated_at, | |
students.grade AS student_grade, | |
students.class AS student_class, | |
students.name AS student_name, | |
classes.address AS class_address, | |
schools.name AS school_name, | |
schools.address AS school_address | |
` | |
err := db.Model(&Student{}).Select(fields). | |
Joins("INNER JOIN classes ON students.class_id = classes.id"). | |
Joins("INNER JOIN schools ON classes.school_id= schools.id"). | |
Scan(&results).Error | |
if err != nil { | |
panic(err) | |
} | |
fmt.Print("listAllStudentInfo: ") | |
for _, r := range results { | |
fmt.Printf("%s\n", marshalIndent(struct { | |
Student Student | |
Class Class | |
School School | |
}{Student: r.Student, Class: r.Class, School: r.School})) | |
} | |
} | |
func listAllStudentInfoUnderGrade(db *gorm.DB, grade uint8) { | |
var results []StudentInfo | |
fields := ` | |
students.id AS student_id, | |
students.created_at AS student_created_at, | |
students.updated_at AS student_updated_at, | |
students.grade AS student_grade, | |
students.class AS student_class, | |
students.name AS student_name, | |
classes.address AS class_address, | |
schools.name AS school_name, | |
schools.address AS school_address | |
` | |
err := db.Model(&Student{}).Select(fields). | |
Joins("INNER JOIN classes ON students.class_id = classes.id"). | |
Joins("INNER JOIN schools ON classes.school_id= schools.id"). | |
Where("classes.grade = ?", grade). | |
Scan(&results).Error | |
if err != nil { | |
panic(err) | |
} | |
fmt.Print("listAllStudentInfoUnderGrade: ") | |
for _, r := range results { | |
fmt.Printf("%s\n", marshalIndent(struct { | |
Student Student | |
Class Class | |
School School | |
}{Student: r.Student, Class: r.Class, School: r.School})) | |
} | |
} | |
func marshalIndent(val interface{}) string { | |
pretty, _ := json.MarshalIndent(val, "", "\t") | |
return string(pretty) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"errors" | |
"fmt" | |
"strings" | |
"time" | |
"gorm.io/gorm" | |
) | |
type School struct { | |
ID uint64 `gorm:"primaryKey"` | |
CreatedAt time.Time | |
UpdatedAt time.Time | |
DeletedAt gorm.DeletedAt `gorm:"index"` | |
Name string `gorm:"size:50;not null;index"` | |
Address string `gorm:"size:200;not null;default:''"` | |
} | |
func (s *School) BeforeSave(tx *gorm.DB) (err error) { | |
fmt.Printf("School BeforeSave: %+v\n", s) | |
return | |
} | |
func (s *School) AfterSave(tx *gorm.DB) (err error) { | |
fmt.Printf("School AfterSave: %+v\n", s) | |
return | |
} | |
func (s *School) validate() (err error) { | |
s.Name = strings.TrimSpace(s.Name) | |
s.Address = strings.TrimSpace(s.Address) | |
if s.Name == "" || s.Address == "" { | |
return errors.New("Invalid arguments") | |
} | |
return | |
} | |
func (s *School) BeforeCreate(tx *gorm.DB) (err error) { | |
fmt.Printf("School BeforeCreate: %+v\n", s) | |
return s.validate() | |
} | |
func (s *School) AfterCreate(tx *gorm.DB) (err error) { | |
fmt.Printf("School AfterCreate: %+v\n", s) | |
return | |
} | |
func (s *School) BeforeUpdate(tx *gorm.DB) (err error) { | |
fmt.Printf("School BeforeUpdate: %+v\n", s) | |
return s.validate() | |
} | |
func (s *School) AfterUpdate(tx *gorm.DB) (err error) { | |
fmt.Printf("School AfterUpdate: %+v\n", s) | |
return | |
} | |
func (s *School) BeforeDelete(tx *gorm.DB) (err error) { | |
fmt.Printf("School BeforeDelete: %+v\n", s) | |
return | |
} | |
func (s *School) AfterDelete(tx *gorm.DB) (err error) { | |
fmt.Printf("School AfterDelete: %+v\n", s) | |
return | |
} | |
func (s *School) AfterFind(tx *gorm.DB) (err error) { | |
fmt.Printf("School AfterFind: %+v\n", s) | |
return | |
} | |
type Class struct { | |
ID uint64 `gorm:"primaryKey"` | |
CreatedAt time.Time | |
UpdatedAt time.Time | |
DeletedAt gorm.DeletedAt `gorm:"index"` | |
Grade uint8 `gorm:"uniqueIndex:idx_grade_class_schoolid,priority:1"` //年 grade, class, school_id | |
Class uint8 `gorm:"uniqueIndex:idx_grade_class_schoolid,priority:2"` //班 | |
SchoolId uint64 `gorm:"uniqueIndex:idx_grade_class_schoolid,priority:3;index"` | |
Address string `gorm:"size:200;not null;default:''"` | |
} | |
func (c *Class) BeforeCreate(tx *gorm.DB) (err error) { | |
fmt.Printf("Class BeforeCreate: %+v\n", c) | |
var school School | |
err = tx.First(&school, c.SchoolId).Error | |
return | |
} | |
type Student struct { | |
ID uint64 `gorm:"primaryKey"` | |
CreatedAt time.Time | |
UpdatedAt time.Time | |
DeletedAt gorm.DeletedAt `gorm:"index"` | |
ClassId uint64 `gorm:"index:idx_classid_schoolid,priority:1"` // class_id, school_id | |
SchoolId uint64 `gorm:"index:idx_classid_schoolid,priority:2;index"` | |
Grade uint8 `gorm:"index:idx_grade_class,priority:1"` //年 grade, class, school_id | |
Class uint8 `gorm:"index:idx_grade_class,priority:2"` //班 | |
Name string `gorm:"index;size:50;not null"` | |
} | |
func (s *Student) BeforeCreate(tx *gorm.DB) (err error) { | |
fmt.Printf("Student BeforeCreate: %+v\n", s) | |
var class Class | |
ret := tx.Model(&Class{}).Where("grade = ? AND class = ? AND school_id = ?", s.Grade, s.Class, s.SchoolId).Select("id").Find(&class) | |
if ret.Error != nil { | |
return ret.Error | |
} | |
if ret.RowsAffected == 0 { | |
return gorm.ErrRecordNotFound | |
} | |
s.ClassId = class.ID | |
return | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment