数据实体
对于Gorm来说,数据Model不仅仅可以是像type User struct { ID int; Name string;} 这种常规方式去定义结构体,也可以做一些特殊操作,如下:
type User struct {
Email *string
Birthday *time.Time
MemberNumber sql.NullString
ActivatedAt sql.NullTime
CreatedAt time.Time
}
*string 和 *time.Time类型的指针表示可空字段,来自sql.NullString和sql.NullTime用于处理可空字符串和时间。CreatedAt是特殊字段,当记录被创建或更新时,GORM 会自动向内填充当前时间。
另外go的结构体还支持用``来标注字段,来让结构体转化为JSON时,key为指定的其它值而不是字段原本的名称。不过这个并不是gorm提供的专属功能。
``符号还有一些妙用,可以用来做权限控制。代码说明如下:
type User struct {
Name string `gorm:"<-:create"` // 允许读和创建
Name string `gorm:"<-:update"` // 允许读和更新
Name string `gorm:"<-"` // 允许读和写(创建和更新)
Name string `gorm:"<-:false"` // 允许读,禁止写
Name string `gorm:"->"` // 只读(除非有自定义配置,否则禁止写)
Name string `gorm:"->;<-:create"` // 允许读和写
Name string `gorm:"->:false;<-:create"` // 仅创建(禁止从 db 读)
Name string `gorm:"-"` // 通过 struct 读写会忽略该字段
Name string `gorm:"-:all"` // 通过 struct 读写、迁移会忽略该字段
Name string `gorm:"-:migration"` // 通过 struct 迁移会忽略该字段
}
以上代码来自官网文档。
增删改查
增加
前一篇文章说过,Create方法可以用来插入数据。实际上create也可以批量插入数据,形如:
users := []*User{
{Name: "Jinzhu", Age: 18, Birthday: time.Now()},
{Name: "Jackson", Age: 19, Birthday: time.Now()},
}
result := db.Create(users)
注意这里传入的参数是切片。
另外还可以只插入指定数据,例如db.Select("Name", "Age", "CreatedAt").Create(&user)就只会插入"Name", "Age", "CreatedAt"三个属性。
查询
GORM 提供了 First、Take、Last 方法,它们本质上都是在查询语句后面加了一个 LIMIT 1.
First和Last方法会按主键排序找到第一条记录和最后一条记录。而Take则没有指定。
要想查询全部对象,可以使用Find方法。
// Get first matched record
db.Where("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;
另外这个例子还展示了gorm独特的查询语句构造方法,内容较多,具体可参阅官方文档。
此外还有Order()、Limit()、Group()等方法,相信一看名字就很好理解了。
修改
Save 会保存所有的字段,即使字段是零值
db.First(&user)
user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)
这一段代码会把First()找到的user更新为如上的数据。save是一个组合函数。如果保存值不包含主键,将执行Create,否则执行Update。
使用Update可以更新单列,Updates方法支持 struct和map[string]interface{}参数更新多列。
删除
删除一条记录时,删除对象需要指定主键,否则会触发批量删除,例如:
// Email 的 ID 是 `10`
db.Delete(&email)
// DELETE from emails where id = 10;
// 带额外条件的删除
db.Where("name = ?", "jinzhu").Delete(&email)
// DELETE from emails where id = 10 AND name = "jinzhu";
本质上删除操作还是查询,只不过最后执行了Delete方法而已。