03-模型

1. 模型

1.1. 模型定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
type User struct {
gorm.Model
Birthday time.Time
Age int
Name string `gorm:"size:255"` // string默认长度为255, 使用这种tag重设。
Num int `gorm:"AUTO_INCREMENT"` // 自增

CreditCard CreditCard // One-To-One (拥有一个 - CreditCard表的UserID作外键)
Emails []Email // One-To-Many (拥有多个 - Email表的UserID作外键)

BillingAddress Address // One-To-One (属于 - 本表的BillingAddressID作外键)
BillingAddressID sql.NullInt64

ShippingAddress Address // One-To-One (属于 - 本表的ShippingAddressID作外键)
ShippingAddressID int

IgnoreMe int `gorm:"-"` // 忽略这个字段
Languages []Language `gorm:"many2many:user_languages;"` // Many-To-Many , 'user_languages'是连接表
}

type Email struct {
ID int
UserID int `gorm:"index"` // 外键 (属于), tag `index`是为该列创建索引
Email string `gorm:"type:varchar(100);unique_index"` // `type`设置sql类型, `unique_index` 为该列设置唯一索引
Subscribed bool
}

type Address struct {
ID int
Address1 string `gorm:"not null;unique"` // 设置字段为非空并唯一
Address2 string `gorm:"type:varchar(100);unique"`
Post sql.NullString `gorm:"not null"`
}

type Language struct {
ID int
Name string `gorm:"index:idx_name_code"` // 创建索引并命名,如果找到其他相同名称的索引则创建组合索引
Code string `gorm:"index:idx_name_code"` // `unique_index` also works
}

type CreditCard struct {
gorm.Model
UserID uint
Number string
}

1.2. 约定

1.2.1. gorm.Model 结构体

基本模型定义gorm.Model,包括字段ID,CreatedAt,UpdatedAt,DeletedAt,你可以将它嵌入你的模型,或者只写你想要的字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 基本模型的定义
type Model struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time
}

// 添加字段 `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt`
type User struct {
gorm.Model
Name string
}

// 只需要字段 `ID`, `CreatedAt`
type User struct {
ID uint
CreatedAt time.Time
Name string
}
1.2.2. 表名是结构体名称的复数形式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
type User struct {} // 默认表名是`users`

// 设置User的表名为`profiles`
func (User) TableName() string {
return "profiles"
}

func (u User) TableName() string {
if u.Role == "admin" {
return "admin_users"
} else {
return "users"
}
}

// 全局禁用表名复数
db.SingularTable(true) // 如果设置为true,`User`的默认表名为`user`,使用`TableName`设置的表名不受影响
1.2.3. 更改默认表名

您可以通过定义DefaultTableNameHandler对默认表名应用任何规则。

1
2
3
gorm.DefaultTableNameHandler = func (db *gorm.DB, defaultTableName string) string  {
return "prefix_" + defaultTableName;
}
1.2.4. 列名是字段名的蛇形小写
1
2
3
4
5
6
7
8
9
10
11
12
13
type User struct {
ID uint // 列名为 `id`
Name string // 列名为 `name`
Birthday time.Time // 列名为 `birthday`
CreatedAt time.Time // 列名为 `created_at`
}

// 重设列名
type Animal struct {
AnimalId int64 `gorm:"column:beast_id"` // 设置列名为`beast_id`
Birthday time.Time `gorm:"column:day_of_the_beast"` // 设置列名为`day_of_the_beast`
Age int64 `gorm:"column:age_of_the_beast"` // 设置列名为`age_of_the_beast`
}
1.2.5. 字段ID为主键
1
2
3
4
5
6
7
8
9
10
11
type User struct {
ID uint // 字段`ID`为默认主键
Name string
}

// 使用tag`primary_key`用来设置主键
type Animal struct {
AnimalId int64 `gorm:"primary_key"` // 设置AnimalId为主键
Name string
Age int64
}
1.2.6. 字段CreatedAt用于存储记录的创建时间

创建具有CreatedAt字段的记录将被设置为当前时间

1
2
3
4
db.Create(&user) // 将会设置`CreatedAt`为当前时间

// 要更改它的值, 你需要使用`Update`
db.Model(&user).Update("CreatedAt", time.Now())
1.2.7. 字段UpdatedAt用于存储记录的修改时间

保存具有UpdatedAt字段的记录将被设置为当前时间

1
2
db.Save(&user) // 将会设置`UpdatedAt`为当前时间
db.Model(&user).Update("name", "jinzhu") // 将会设置`UpdatedAt`为当前时间
1.2.8. 字段DeletedAt用于存储记录的删除时间

如果字段存在,删除具有DeletedAt字段的记录,它不会冲数据库中删除,但只将字段DeletedAt设置为当前时间,并在查询时无法找到记录,请参阅软删除

1.3. 关联

1.3.1. 属于
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// `User`属于`Profile`, `ProfileID`为外键
type User struct {
gorm.Model
Profile Profile
ProfileID int
}

type Profile struct {
gorm.Model
Name string
}

db.Model(&user).Related(&profile)
//// SELECT * FROM profiles WHERE id = 111; // 111是user的外键ProfileID

指定外键

1
2
3
4
5
6
7
8
9
10
type Profile struct {
gorm.Model
Name string
}

type User struct {
gorm.Model
Profile Profile `gorm:"ForeignKey:ProfileRefer"` // 使用ProfileRefer作为外键
ProfileRefer int
}

指定外键和关联外键

1
2
3
4
5
6
7
8
9
10
11
type Profile struct {
gorm.Model
Refer string
Name string
}

type User struct {
gorm.Model
Profile Profile `gorm:"ForeignKey:ProfileID;AssociationForeignKey:Refer"`
ProfileID int
}
1.3.2. 包含一个
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// User 包含一个 CreditCard, UserID 为外键
type User struct {
gorm.Model
CreditCard CreditCard
}

type CreditCard struct {
gorm.Model
UserID uint
Number string
}

var card CreditCard
db.Model(&user).Related(&card, "CreditCard")
//// SELECT * FROM credit_cards WHERE user_id = 123; // 123 is user's primary key
// CreditCard是user的字段名称,这意味着获得user的CreditCard关系并将其填充到变量
// 如果字段名与变量的类型名相同,如上例所示,可以省略,如:
db.Model(&user).Related(&card)

指定外键

1
2
3
4
5
6
7
8
9
10
type Profile struct {
gorm.Model
Name string
UserRefer uint
}

type User struct {
gorm.Model
Profile Profile `gorm:"ForeignKey:UserRefer"`
}

指定外键和关联外键

1
2
3
4
5
6
7
8
9
10
11
type Profile struct {
gorm.Model
Name string
UserID uint
}

type User struct {
gorm.Model
Refer string
Profile Profile `gorm:"ForeignKey:UserID;AssociationForeignKey:Refer"`
}
1.3.3. 包含多个
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// User 包含多个 emails, UserID 为外键
type User struct {
gorm.Model
Emails []Email
}

type Email struct {
gorm.Model
Email string
UserID uint
}

db.Model(&user).Related(&emails)
//// SELECT * FROM emails WHERE user_id = 111; // 111 是 user 的主键

指定外键

1
2
3
4
5
6
7
8
9
10
type Profile struct {
gorm.Model
Name string
UserRefer uint
}

type User struct {
gorm.Model
Profiles []Profile `gorm:"ForeignKey:UserRefer"`
}

指定外键和关联外键

1
2
3
4
5
6
7
8
9
10
11
type Profile struct {
gorm.Model
Name string
UserID uint
}

type User struct {
gorm.Model
Refer string
Profiles []Profile `gorm:"ForeignKey:UserID;AssociationForeignKey:Refer"`
}
1.3.4. 多对多
1
2
3
4
5
6
7
8
9
10
11
12
13
// User 包含并属于多个 languages, 使用 `user_languages` 表连接
type User struct {
gorm.Model
Languages []Language `gorm:"many2many:user_languages;"`
}

type Language struct {
gorm.Model
Name string
}

db.Model(&user).Related(&languages, "Languages")
//// SELECT * FROM "languages" INNER JOIN "user_languages" ON "user_languages"."language_id" = "languages"."id" WHERE "user_languages"."user_id" = 111

指定外键和关联外键

1
2
3
4
5
6
7
8
9
type CustomizePerson struct {
IdPerson string `gorm:"primary_key:true"`
Accounts []CustomizeAccount `gorm:"many2many:PersonAccount;ForeignKey:IdPerson;AssociationForeignKey:IdAccount"`
}

type CustomizeAccount struct {
IdAccount string `gorm:"primary_key:true"`
Name string
}
1.3.5 多种包含

支持多种的包含一个和包含多个的关联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type Cat struct {
Id int
Name string
Toy Toy `gorm:"polymorphic:Owner;"`
}

type Dog struct {
Id int
Name string
Toy Toy `gorm:"polymorphic:Owner;"`
}

type Toy struct {
Id int
Name string
OwnerId int
OwnerType string
}

注意:多态属性和多对多显式不支持,并且会抛出错误。

1.3.6. 关联模式

关联模式包含一些帮助方法来处理关系事情很容易。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 开始关联模式
var user User
db.Model(&user).Association("Languages")
// `user`是源,它需要是一个有效的记录(包含主键)
// `Languages`是关系中源的字段名。
// 如果这些条件不匹配,将返回一个错误,检查它:
// db.Model(&user).Association("Languages").Error


// Query - 查找所有相关关联
db.Model(&user).Association("Languages").Find(&languages)


// Append - 添加新的many2many, has_many关联, 会替换掉当前 has_one, belongs_to关联
db.Model(&user).Association("Languages").Append([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Append(Language{Name: "DE"})


// Delete - 删除源和传递的参数之间的关系,不会删除这些参数
db.Model(&user).Association("Languages").Delete([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Delete(languageZH, languageEN)


// Replace - 使用新的关联替换当前关联
db.Model(&user).Association("Languages").Replace([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Replace(Language{Name: "DE"}, languageEN)


// Count - 返回当前关联的计数
db.Model(&user).Association("Languages").Count()


// Clear - 删除源和当前关联之间的关系,不会删除这些关联
db.Model(&user).Association("Languages").Clear()

03-模型
https://flepeng.github.io/021-Go-34-框架-41-Gorm-V1-03-模型/
作者
Go
发布于
2024年11月15日
许可协议