ä¸Âç¯ÂæÂÂç« ç®ÂÃ¥ÂÂäºÂ解gormæ¡Âæ¶
ä»Âä¹Âæ¯ORM
æÂÂè°ÂORMå³æ¯ Object Relational Mappingï¼Â对象堳系æ å°Âï¼Âä¹Âå°±æ¯说ç»ÂæÂÂä½ å SQLæ°æ®åºÂÃ¥ÂÂå¨æ å°Âï¼Âè¿Â个æ¶åÂÂå°±æÂÂäºÂORMè¯ÂÃ¥ÂÂ¥
ä¹Âå°±æ¯说æÂÂè°ÂORMå°±æ¯建ç«Âæ°æ®åºÂä¸Â表æ°æ®ä¸Â代ç Âä¸Âç»ÂæÂÂä½Â建ç«ÂçÂÂ堳系
ä»Âä¹Âæ¯gormæ¡Âæ¶
gormå®Âæ¹ä¸ÂæÂÂæÂÂæ¡£å°åÂÂ
GORMï¼ÂGo Object Relational Mappingï¼Âæ¯ä¸Â个åº亠Go è¯Âè¨ÂçÂÂàORMàæ¡Âæ¶ï¼Âç¨äºÂç®ÂÃ¥ÂÂæ°æ®访é®åÂÂæÂÂä¹ åÂÂçÂÂè¿Âç¨ÂãÂÂå®ÂæÂÂä¾ÂäºÂä¸Âç§Âç®ÂÃ¥ÂÂãÂÂçµ活åÂÂ强大çÂÂæ¹å¼Âæ¥管çÂÂæ°æ®åºÂï¼ÂÃ¥ÂÂæ¶ä¹Âæ¯æÂÂå¤Âç§Âæ°æ®åºÂï¼Â妠MySQLãÂÂPostgreSQLãÂÂSQLiteãÂÂSQL Server çÂÂãÂÂ
GORM æÂÂä¾ÂäºÂä¸Âç»ÂæÂÂäºÂ使ç¨ç APIï¼Âå¯以éÂÂè¿Âç»ÂæÂÂä½ÂÃ¥ÂÂæ Âç¾æÂ¥å®Âä¹Âæ°æ®åºÂ表åÂÂÃ¥ÂÂ段ï¼Âä»ÂèÂÂå®Âç°æ°æ®åºÂç CRUD æÂÂä½ÂãÂÂå®Âè¿Âæ¯æÂÂäºÂå¡ãÂÂé¢Âå 载ãÂÂèÂÂ表æ¥询ãÂÂÃ¥ÂÂ页æ¥询ãÂÂ软å é¤ãÂÂèªå¨è¿Â移åÂÂé©åÂÂçÂÂÃ¥ÂÂè½ï¼Â以满足åÂÂç§ÂåºÂç¨ç¨ÂåºÂçÂÂéÂÂæ±ÂãÂÂgormæ¯ä¸Â个使ç¨Goè¯Âè¨Âç¼ÂÃ¥ÂÂçÂÂORMæ¡Âæ¶ãÂÂå®ÂæÂÂæ¡£é½Âå ¨ï¼Â对å¼ÂÃ¥ÂÂè åÂÂ好ï¼Âæ¯æÂÂ主æµÂæ°æ®åºÂãÂÂ
å®Â裠gorm
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
è¿ÂæÂ¥æ°æ®åºÂï¼Â以mysql为ä¾ÂÃ¥ÂÂï¼Â
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/schema"
"time"
)
func main() {
//dsnå°±æ¯æÂÂå®ÂäºÂæ°æ®åºÂçÂÂä¸ÂäºÂéÂ
Âç½®ï¼Âæ¯Âå¦Â说访é®æ°æ®åºÂçÂÂç¨æ·ï¼Âå¯Âç Âï¼Â以åÂÂåºÂçÂÂÃ¥ÂÂÃ¥ÂÂç¼Âç Âæ¹å¼ÂçÂÂ
dsn := "root:3356@tcp(127.0.0.1:3306)/minitok?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.New(mysql.Config{
DSN: dsn, // DSN data source name//æÂÂ为åÂ
³é®çÂÂä¸ÂæÂ¥ï¼ÂéÂ
Âç½®DSN
DefaultStringSize: 256, // string ç±»åÂÂÃ¥ÂÂ段çÂÂé»Â认é¿度
DisableDatetimePrecision: true, // ç¦Âç¨ datetime 精度ï¼ÂMySQL 5.6 ä¹ÂÃ¥ÂÂçÂÂæ°æ®åºÂä¸Âæ¯æÂÂ
DontSupportRenameIndex: true, // éÂÂå½åÂÂç´¢å¼Âæ¶éÂÂç¨å é¤并æ°建çÂÂæ¹å¼Âï¼ÂMySQL 5.7 ä¹ÂÃ¥ÂÂçÂÂæ°æ®åºÂå MariaDB ä¸Âæ¯æÂÂéÂÂå½åÂÂç´¢å¼Â
DontSupportRenameColumn: true, // ç¨ `change` éÂÂå½åÂÂÃ¥ÂÂï¼ÂMySQL 8 ä¹ÂÃ¥ÂÂçÂÂæ°æ®åºÂå MariaDB ä¸Âæ¯æÂÂéÂÂå½åÂÂÃ¥ÂÂ
SkipInitializeWithVersion: false, // æ ¹æ®å½Âå MySQL çÂÂ揪å¨éÂ
Âç½®
}), &gorm.Config{
SkipDefaultTransaction: false,
NamingStrategy: schema.NamingStrategy{
TablePrefix: "t_",
SingularTable: false,
},
DisableForeignKeyConstraintWhenMigrating: true,
})
fmt.Println(db, err)
}
å®Âé ä¸ÂéÂÂè¿Âgormè¿ÂæÂ¥æ°æ®åºÂæ¯åÂÂÃ¥ÂÂç®ÂÃ¥ÂÂçÂÂï¼ÂæÂÂæ ¸å¿ÂçÂÂä¸ÂæÂ¥æ¯æ£确çÂÂé Âç½®DSNå³å¯
å¨ GORM ä¸Âï¼ÂDSNï¼ÂData SourceàNameï¼Âæ¯ä¸Âç§Âç¨äºÂè¿ÂæÂ¥æ°æ®åºÂçÂÂÃ¥ÂÂ符串格å¼Âï¼Âå å«äºÂè¿ÂæÂ¥æ°æ®åºÂæÂÂéÂÂçÂÂÃ¥ÂÂæ°åÂÂä¿¡æ¯ãÂÂDSN æ ¼å¼ÂçÂÂå ·ä½Âå 容ä¼Âæ ¹æ®ä¸ÂÃ¥ÂÂçÂÂæ°æ®åºÂç±»åÂÂèÂÂæÂÂæÂÂä¸ÂÃ¥ÂÂï¼Âä½ÂéÂÂ常å æ¬以ä¸Âä¿¡æ¯ï¼Â
- æ°æ®åºÂç±»åÂÂï¼Â妠MySQLãÂÂPostgreSQLãÂÂSQLiteãÂÂSQL Server çÂÂï¼Â
- æ°æ®åºÂç¨æ·åÂÂÃ¥ÂÂå¯Âç Â
- æ°æ®åºÂå°åÂÂÃ¥ÂÂ端å£å·
- æ°æ®åºÂÃ¥ÂÂ称
- å ¶ä»Âè¿ÂæÂ¥éÂÂ项ï¼Â妠SSL éÂÂ项çÂÂï¼Â
å¨ GORM ä¸Âï¼ÂéÂÂè¿Âå¨àOpen()
àæ¹æ³Âä¸Âä¼ é DSN Ã¥ÂÂ符串ï¼Âå¯以æÂÂå¼Âä¸Â个æ°æ®åºÂè¿ÂæÂ¥ãÂÂä¾Âå¦Âï¼Âå¨è¿ÂæÂ¥å° MySQL æ°æ®åºÂæ¶ï¼Âå¯以使ç¨以丠DSN æ ¼å¼Âï¼Â
"username:password@tcp(host:port)/database?charset=utf8&parseTime=True&loc=Local"
Ã¥Â
¶ä¸Âï¼Âusername
àåÂÂàpassword
àåÂÂå«为æ°æ®åºÂçÂÂç¨æ·åÂÂÃ¥ÂÂå¯Âç Âï¼Âhost
àåÂÂàport
àåÂÂå«为æ°æ®åºÂçÂÂå°åÂÂÃ¥ÂÂ端å£å·ï¼Âdatabase
à为è¦Âè¿ÂæÂ¥çÂÂæ°æ®åºÂÃ¥ÂÂ称ãÂÂcharset=utf8
à表示使ç¨ UTF-8 ç¼Âç Âï¼ÂparseTime=True
à表示èªå¨解æÂÂæ¶é´类åÂÂï¼Âloc=Local
à表示使ç¨æΡæ¶åºãÂÂ
å¨å®Âé 使ç¨ä¸Âï¼Âå¯以根æ®堷ä½ÂçÂÂæ°æ®åºÂç±»åÂÂÃ¥ÂÂéÂÂæ±Âæ¥设置ä¸ÂÃ¥ÂÂç DSN Ã¥ÂÂ符串ãÂÂGORM æ¯æÂÂå¤Âç§Âæ°æ®åºÂï¼Âå æ¤å¯以å¨ä¸ÂÃ¥ÂÂçÂÂåºÂç¨åºæ¯ä¸Âçµ活åÂÂæ¢åÂÂ使ç¨ãÂÂ
æ¤å¤Âï¼Âgormå®Âä¹ÂäºÂ许å¤ÂæÂÂä½Âæ°æ®åºÂçÂÂæÂ¥å£,æ¯Âå¦Âdb.create(&User{})
…çÂÂï¼Âå¯以èªè¡ÂæÂ¥éÂÂ
å®Âæ¹æÂÂæ¡£èªè¡Âè¿Âè¡Âä¸ÂæÂÂå®Âè·µãÂÂ
Ã¥ÂÂ建æ°æ®åºÂï¼Â
å¨æÂÂ们使ç¨GROM
ä¹ÂÃ¥ÂÂæÂÂ们åºÂ该åÂ
ÂÃ¥ÂÂ建好ç¸åºÂçÂÂæ°æ®åºÂ
CREATE DATABASE db1
ç¶åÂÂÃ¥ÂÂ使ç¨GORM
è¿ÂæÂ¥æÂÂä½Âæ°æ®åºÂ
package main
âÂÂ
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/schema"
"time"
)
âÂÂ
// UserInfo ç¨æ·信æ¯
type UserInfo struct {
ID uint
Name string
Gender string
Hobby string
}
âÂÂ
âÂÂ
func main() {
db, err := gorm.Open("mysql", "root:root1234@(127.0.0.1:13306)/db1?charset=utf8mb4&parseTime=True&loc=Local")
//DSNéÂÂè¦Âæ ¹æ®èª己çÂÂéÂ
Âç½®è¿Âè¡Âæ´æ¹
if err!= nil{
panic(err)
}
defer db.Close()
âÂÂ
// èªå¨è¿Â移
db.AutoMigrate(&UserInfo{})
âÂÂ
u1 := UserInfo{2023, "Nanami", "女", "游æÂÂ"}
u2 := UserInfo{2024, "Sakana", "女", "游泳"}
// Ã¥ÂÂ建记å½Â
db.Create(&u1)
db.Create(&u2)
// æ¥询
var u = new(UserInfo)
db.First(u)
fmt.Printf("%#v\n", u)
âÂÂ
var uu UserInfo
db.Find(&uu, "hobby=?", "足çÂÂ")
fmt.Printf("%#v\n", uu)
âÂÂ
// æ´æ°
db.Model(&u).Update("hobby", "Ã¥ÂÂè²çÂÂ")
// å é¤
db.Delete(&u)
}
ä¸Â述代ç Âç®ÂÃ¥ÂÂçÂÂæ¼Â示äºÂä»Âè¿ÂæÂ¥æ°æ®åºÂå°对æ°æ®åºÂè¿Âè¡Âç®ÂÃ¥ÂÂçÂÂå¢Âå æ¹æÂ¥æÂÂä½ÂçÂÂè¿Âç¨Âï¼Â
æ´å¤ÂçÂÂä¾ÂÃ¥ÂÂ请æÂ¥é å®Âæ¹æÂÂæ¡£.
GORM Model
å®Âä¹Â
å¨使ç¨ORM
æ¡Âæ¶çÂÂæ¶åÂÂï¼ÂæÂÂ们éÂÂ常éÂÂè¦Âå¨代ç Âä¸Âå®Âä¹Â模åÂÂå³Model
æÂ¥ä¸Âæ°æ®åºÂä¸ÂçÂÂ表åÂÂè¿Âè¡Âæ å°Â
ï¼Âå¨GORM
æ¡Âæ¶ä¸ÂModels
éÂÂ常æ¯æ£常å®Âä¹ÂçÂÂç»ÂæÂÂä½ÂãÂÂåºæÂÂgoç±»åÂÂæÂÂèÂÂ
å®Â们çÂÂæÂÂéÂÂãÂÂ
为äºÂ使å®Âä¹Âæ°æ®åºÂ表åÂÂæ´å è§ÂèÂÂï¼ÂGORMÃ¥ÂÂ
ç½®äºÂä¸Â个gorm.Model
ç»ÂæÂÂä½ÂãÂÂä»ÂçÂÂå®Âä¹Âå¦Âä¸Âï¼Â
// gorm.Model å®Âä¹Â
type Model struct {
ÃÂ ID ÃÂ ÃÂ ÃÂ ÃÂ uint `gorm:"primary_key"`
ÃÂ CreatedAt time.Time
ÃÂ UpdatedAt time.Time
ÃÂ DeletedAt *time.Time
}
ä½ å¯以æÂÂgorm.Model
å¿åÂÂåµÂÃ¥Â
¥å°èª己çÂÂç»ÂæÂÂä½Âä¹Âä¸Â
type BasicInfo struct {
Time time.Time `gorm:"column:basic_time"`
Basic_sentence string `gorm:"primaryKey"`
}
type User struct {
gorm.Model
infos BasicInfo `gorm:"embedded;embeddedPrefix:em_"`
Nickname string
Email *string
Age uint8
}
å¨è°Âç¨db.AutoMigrate{&User{}}
ä¹ÂÃ¥ÂÂÃ¥ÂÂæ¥询æ°æ®åºÂä¹Âä¸ÂçÂÂ表åÂÂå¯以çÂÂå°ä¸Âä¸Âç»ÂæÂÂæ¯符åÂÂæÂÂ们é¢ÂæÂÂçÂÂãÂÂ
mysql> describe t_users;
+----------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| created_at | datetime | YES | | NULL | |
| updated_at | datetime | YES | | NULL | |
| deleted_at | datetime | YES | MUL | NULL | |
| basic_time | datetime | YES | | NULL | |
| basic_sentence | varchar(256) | NO | PRI | NULL | |
| nickname | varchar(256) | YES | | NULL | |
| email | varchar(256) | YES | | NULL | |
| age | tinyint(3) unsigned | YES | | NULL | |
+----------------+---------------------+------+-----+---------+----------------+
9 rows in set (0.00 sec)
顺带å¼Âå ¥ç»ÂæÂÂä½Âæ Âè®°(tags)çÂÂä»Âç»Â
详ç»Âå®Âæ´çÂÂä»Âç»Â请ç¹å»è¿ÂéÂÂ
gorm:"column:xxx"
ï¼ÂæÂÂå®Âæ°æ®åºÂ表ä¸Â对åºÂÃ¥ÂÂ段çÂÂÃ¥ÂÂ称ãÂÂä¾Âå¦Âï¼Âgorm:"column:user_name"
à表示å°Âç»ÂæÂÂä½ÂÃ¥ÂÂ段æ å°Âå°æ°æ®åºÂ表ä¸ÂçÂÂÃÂuser_name
àåÂÂ段ãÂÂgorm:"type:xxx"
ï¼ÂæÂÂå®Âæ°æ®åºÂÃ¥ÂÂ段çÂÂæ°æ®类åÂÂãÂÂä¾Âå¦Âï¼Âgorm:"type:int"
à表示å°Âç»ÂæÂÂä½ÂÃ¥ÂÂ段æ å°Âå°æ°æ®åºÂ表ä¸ÂçÂÂÃÂint
à类åÂÂÃ¥ÂÂ段ãÂÂgorm:"size:xxx"
ï¼ÂæÂÂå®Âæ°æ®åºÂÃ¥ÂÂ段çÂÂé¿度æÂÂ大å°ÂãÂÂä¾Âå¦Âï¼Âgorm:"size:255"
à表示å°Âç»ÂæÂÂä½ÂÃ¥ÂÂ段æ å°Âå°æ°æ®åºÂ表ä¸ÂçÂÂé¿度为 255 çÂÂÃ¥ÂÂ段ãÂÂgorm:"not null"
ï¼ÂæÂÂå®Âæ°æ®åºÂÃ¥ÂÂ段ä¸Âè½为空ãÂÂä¾Âå¦Âï¼Âgorm:"not null"
à表示å°Âç»ÂæÂÂä½ÂÃ¥ÂÂ段æ å°Âå°æ°æ®åºÂ表ä¸ÂçÂÂéÂÂ空åÂÂ段ãÂÂgorm:"default:xxx"
ï¼ÂæÂÂå®Âæ°æ®åºÂÃ¥ÂÂ段çÂÂé»Â认å¼ãÂÂä¾Âå¦Âï¼Âgorm:"default:'unknown'"
à表示å°Âç»ÂæÂÂä½ÂÃ¥ÂÂ段æ å°Âå°æ°æ®åºÂ表ä¸ÂçÂÂé»Â认å¼为ÃÂ'unknown'
àçÂÂÃ¥ÂÂ段ãÂÂgorm:"unique"
ï¼ÂæÂÂå®Âæ°æ®åºÂÃ¥ÂÂ段çÂÂå¯ä¸Âæ§ãÂÂä¾Âå¦Âï¼Âgorm:"unique"
à表示å°Âç»ÂæÂÂä½ÂÃ¥ÂÂ段æ å°Âå°æ°æ®åºÂ表ä¸ÂçÂÂå¯ä¸ÂÃ¥ÂÂ段ãÂÂgorm:"index"
ï¼ÂæÂÂå®Âæ°æ®åºÂÃ¥ÂÂ段çÂÂç´¢å¼ÂãÂÂä¾Âå¦Âï¼Âgorm:"index"
à表示å°Âç»ÂæÂÂä½ÂÃ¥ÂÂ段æ å°Âå°æ°æ®åºÂ表ä¸ÂçÂÂç´¢å¼ÂÃ¥ÂÂ段ãÂÂgorm:"primary_key"
ï¼ÂæÂÂå®Âæ°æ®åºÂÃ¥ÂÂ段为主é®ãÂÂä¾Âå¦Âï¼Âgorm:"primary_key"
à表示å°Âç»ÂæÂÂä½ÂÃ¥ÂÂ段æ å°Âå°æ°æ®åºÂ表ä¸ÂçÂÂ主é®åÂÂ段ãÂÂ
GORM
ä¸ÂçÂÂCURD
CURD
éÂÂ常æÂÂçÂÂæ¯æ°æ®åºÂçÂÂå¢Âå æ¹æÂ¥æÂÂä½Âï¼Âæ¬å°ÂèÂÂå°Âç³»ç»Âå°ä»Âç»Âå¦Âä½Â使ç¨GORM
æÂ¥å®Âç°CURDæÂÂä½Âï¼Â注ï¼Âæ¾ÂÂä¸Âdb
Ã¥ÂÂéÂÂÃ¥Â
¨é¨é»Â认为*gorm.DB
ç±»åÂÂãÂÂ
Ã¥ÂÂ建记å½Â
é¦Âå Âå®Âä¹Âç¸堳Model
type User struct{
ID uint64 `gorm:"primaryKey"`
Name String `gorm:"default:'ä¸Âæµ·'"`
Age uint8
}
æÂ¥çÂÂ使ç¨NewRecord(å®Âä¾Â)
æ¹æ³ÂæÂ¥å¤æÂÂæ£ÂæÂ¥ç»Âå®ÂçÂÂ模åÂÂå®Âä¾Âæ¯å¦æ¯ä¸Â个æ°记å½ÂãÂÂ
user1:=User{Name:"Nanami",Age: 19}
if db.NewRecord(user1){//è¥为æ°纪å½ÂÃ¥ÂÂè¿ÂÃ¥ÂÂtrue
db.Create(&user1)//Ã¥ÂÂ建user1å®Âä¾ÂçÂÂæ°纪å½Â
}
æÂ¥æ¾记å½Â
ä¸Âè¾¥询
//ç¨äºÂä¿ÂÃ¥ÂÂè¿ÂÃ¥ÂÂç»ÂæÂÂ
var user1 User
var users []User
db.First(&user1)//è·åÂÂ表ä¸ÂçÂÂ第ä¸Âæ¡记å½Â
db.Take(&user1)//éÂÂæºè·åÂÂä¸Âæ¡æ°æ®
db.Last(&user1)//æÂ¥æ¾主é®æÂÂåºÂçÂÂæÂÂÃ¥ÂÂä¸Âæ¡记å½Â
db,Find(&usres)//æÂ¥æ¾æÂÂæÂÂè®°å½Â
使ç¨Where
è¿Âè¡Âæ¡件æÂ¥æ¾
db.Where("name=?","Nanami").Fisrt(&user1)
//çÂÂä»·äºÂSELECT * FROM t_users WHERE name='Nanami' LIMIT 1(ä¸Âé¢çÂÂè¯Âå¥ä¹Â类似)
db.Where("name<>?","ä¸Âæµ·").find(&users)
db.Where("name IN (?)",[]string{"ä¸Âæµ·","Nanami"}).Find(&users)
db.Where("name=? AND age>=?","Nanami",20).Find(&users)
db.Where("created_at BETWEEN ? AND ?",last_Sunday,today).Find(&users)
æ´æ°æ°æ®åºÂ
db.First(&user1)
user1.Name="new_Nanami"
user1.age=100
db.save(&user1)
db.save()
æ¹æ³Âä¼Âé»Â认æ´æ°该对象çÂÂæÂÂæÂÂÃ¥ÂÂ段ï¼Âå³使你没æÂÂèµÂå¼
å¦ÂæÂÂä½ åªæ¯æ³æ´æ°æÂÂå®ÂÃ¥ÂÂ段ï¼Âé£ä¹Âä½ å¯以å°Âè¯Â使ç¨Update
æÂÂèÂÂ
Updates
æ¹æ³Â
db.Model(&user1).Update("name","Nakira")
//ä¸Âè¿°æÂÂ令ä½Âç¨ï¼Âä¿®æ¹user1çÂÂnameÃ¥ÂÂ段å¼为âÂÂNakiraâÂÂ
//éÂÂè¦Â注æÂÂçÂÂæ¯nameæ¯å¨æ°æ®表ä¸ÂçÂÂÃ¥ÂÂçÂÂÃ¥ÂÂ称ï¼ÂèÂÂä¸Âæ¯ç»ÂæÂÂä½ÂçÂÂÃ¥ÂÂ称ï¼Âuser1æ¯æ°æ®åºÂä¸ÂçÂÂå®Âä¾Â
db.Model(&uesr1).Where("active=?",true).Update("name","Nakira")
db.Model(&user2).Update(map[string]interface{}{"name":"Nanami","age":19,"active":false})
//使ç¨mapç»ÂæÂÂæÂ¥å®Âç°æ´æ°å¤Â个å±Âæ§
å¦ÂæÂÂä½ æ³è¦Â忽çÂ¥æÂÂäºÂÃ¥ÂÂ段é£ä¹Âä½ å¯以èÂÂèÂÂ使ç¨Select
,Omit
æÂ¥å®Âç°
db.Model(&user1).Select("name").Update(map[string]interface{}{"name":"Nanami","age":19,"active":false})//éÂÂä¸Âåªæ´æ°nameÃ¥ÂÂ段
db.Model(&user1).Omit("name").Update(map[string]interface{}{"name":"Nanami","age":19,"active":false})//忽çÂ¥æ´æ°nameÃ¥ÂÂ段
å é¤记å½Â
db.Delete(&user1)//å é¤ç°æÂÂè®°å½Â
db.Where("name=?","Nanami").Delete(User{})//æ¹éÂÂå é¤å¹éÂ
ÂçÂÂæ°æ®
æ¬人åÂÂå¦gorm
ï¼Âé¾åÂ
ÂæÂÂéÂÂ误ä¹Âå¤Âï¼Â请åÂÂä½Âå¤Âå¤ÂæÂÂæ£ãÂÂå¤Âå¤ÂÃ¥ÂÂ
涵ãÂÂ2023.7.28