gorm软删除_GORM中文文档-Go语言中文社区

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-1 03:27   11   0

入门指南

GORM是类似Django ORM,对开发人员友好的 Golang ORM 库。

概览

全特性 ORM (几乎包含所有特性)

模型关联 (一对一, 一对多,一对多(反向), 多对多, 多态关联)

钩子 (Before/After Create/Save/Update/Delete/Find)

预加载

事务

复合主键

SQL 构造器

自动迁移

日志

基于 GORM 回调编写可扩展插件

全特性测试覆盖

开发者友好

安装

go get -u github.com/jinzhu/gorm

Quick Start

package main

import (

"github.com/jinzhu/gorm"

_ "github.com/jinzhu/gorm/dialects/sqlite"

)

type Product struct {

gorm.Model// gorm.Model 帮我们定义好了一些字段,如:ID、created_at等等

Code string

Price uint

}

func main() {

db, err := gorm.Open("sqlite3", "test.db")

if err != nil {

panic("failed to connect database")

}

defer db.Close()

//自动检查 Product 结构是否变化,变化则进行迁移

db.AutoMigrate(&Product{})

// 增

db.Create(&Product{Code: "L1212", Price: 1000})

// 查

var product Product

db.First(&product, 1) // 找到id为1的产品

db.First(&product, "code = ?", "L1212") // 找出 code 为 l1212 的产品

// 改 - 更新产品的价格为 2000

db.Model(&product).Update("Price", 2000)

// 删 - 删除产品

db.Delete(&product)

}

模型定义

模型定义

模型一般都是普通的 Golang 的结构体,Go 的基本数据类型,或者指针。sql.Scanner 和 driver.Valuer,同时也支持接口。

例子:

type User struct {

gorm.Model

Name string

Age sql.NullInt64

Birthday *time.Time

Email string `gorm:"type:varchar(100);unique_index"`

Role string `gorm:"size:255"` //设置字段的大小为255个字节

MemberNumber *string `gorm:"unique;not null"` // 设置 memberNumber 字段唯一且不为空

Num int `gorm:"AUTO_INCREMENT"` // 设置 Num字段自增

Address string `gorm:"index:addr"` // 给Address 创建一个名字是 `addr`的索引

IgnoreMe int `gorm:"-"` //忽略这个字段

}

结构标签

标签是声明模型时可选的标记。GORM 支持以下标记:

支持的结构标签

标签

说明Column

指定列的名称

Type

指定列的类型

Size

指定列的大小,默认是 255

PRIMARY_KEY

指定一个列作为主键

UNIQUE

指定一个唯一的列

DEFAULT

指定一个列的默认值

PRECISION

指定列的数据的精度

NOT NULL

指定列的数据不为空

AUTO_INCREMENT

指定一个列的数据是否自增

INDEX

创建带或不带名称的索引,同名创建复合索引

UNIQUE_INDEX

类似 索引,创建一个唯一的索引

EMBEDDED

将 struct 设置为 embedded

EMBEDDED_PREFIX

设置嵌入式结构的前缀名称

-

忽略这些字段

关联的结构标签

有关详细信息,请查看「关联」部分

标签

说明MANY2MANY

指定连接表名称

FOREIGNKEY

指定外键

ASSOCIATION_FOREIGNKEY

指定关联外键

POLYMORPHIC

指定多态类型

POLYMORPHIC_VALUE

指定多态的值

JOINTABLE_FOREIGNKEY

指定连接表的外键

ASSOCIATION_JOINTABLE_FOREIGNKEY

指定连接表的关联外键

SAVE_ASSOCIATIONS

是否自动保存关联

ASSOCIATION_AUTOUPDATE

是否自动更新关联

ASSOCIATION_AUTOCREATE

是否自动创建关联

ASSOCIATION_SAVE_REFERENCE

是否自动保存引用的关联

约定

gorm.Model

gorm.Model 是一个包含一些基本字段的结构体,包含的字段有 ID,CreatedAt, UpdatedAt, DeletedAt。

你可以用它来嵌入到你的模型中,或者也可以组合他它来建立自己的模型。

// gorm.Model 定义

type Model struct {

ID uint `gorm:"primary_key"`

CreatedAt time.Time

UpdatedAt time.Time

DeletedAt *time.Time

}

// 将字段 `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt` 注入到 `User` 模型中

type User struct {

gorm.Model

Name string

}

// 不使用 gorm.Model 模型

type User struct {

ID int

Name string

}

ID 作为主键

GORM 默认使用 ID 作为主键名。

type User struct {

ID string // 字段名 `ID` 将被作为默认的主键名

}

// 设置字段 `AnimalID` 为默认主键

type Animal struct {

AnimalID int64 `gorm:"primary_key"`

Name string

Age int64

}

复数表名

表名是结构体名称的复数形式

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"

}

}

// 如果设置禁用表名复数形式属性为 true,`User` 的表名将是 `user`

db.SingularTable(true)

指定表名

// 用 `User` 结构体创建 `delete_users` 表

db.Table("deleted_users").CreateTable(&User{})

var deleted_users []User

db.Table("deleted_users").Find(&deleted_users)

SELECT * FROM deleted_users;

db.Table("deleted_users").Where("name = ?", "jinzhu").Delete()

DELETE FROM deleted_users WHERE name = 'jinzhu';

修改默认表名

你可以通过定义 DefaultTableNameHandler 字段来对表名使用任何规则。

gorm.DefaultTableNameHandler = func (db *gorm.DB, defaultTableName string) string {

return "prefix_" + defaultTableName;

}

蛇形列名

列名是字段名的蛇形小写(小写字母加下划线)形式

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`

}

时间戳跟踪

CreatedAt

对于有 CreatedAt 字段的模型,它将被设置为首次创建记录的当前时间。

db.Create(&user) // 将设置 `CreatedAt` 为当前时间

// 你可以使用 `Update` 方法来更改默认时间

db.Model(&user).Update("CreatedAt", time.Now())

UpdatedAt

对于有 UpdatedAt 字段的模型,它将被设置为记录更新时的当前时间。

db.Save(&user) // 将设置 `UpdatedAt` 为当前时间

db.Model(&user).Update("name", "jinzhu") // 将设置 `UpdatedAt` 为当前时间

DeletedAt

对于有 DeletedAt 字段的模型,当删除它们的实例时,它们并没有被从数据库中删除,只是将 DeletedAt 字段设置为当前时间。参考 软删除(Soft Delete)。

连接数据库

为了连接数据库,你首先要导入数据库驱动程序。例如:

import _ "github.com/go-sql-driver/mysql"

GORM 已经包含了一些驱动程序,为了方便的去记住它们的导入路径,你可以像下面这样导入 mysql 驱动程序

import _ "github.com/jinzhu/gorm/dialects/mysql"

// import _ "github.com/jinzhu/gorm/dialects/postgres"

// import _ "github.com/jinzhu/gorm/dialects/sqlite"

// import _ "github.com/jinzhu/gorm/dialects/mssql"

支持的数据库

MySQL

注意: 为了正确的处理 time.Time ,你需要包含 parseTime 作为参数。

import (

"github.com/jinzhu/gorm"

_ "github.com/jinzhu/gorm/dialects/mysql"

)

func main() {

db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")

defer db.Close()

}

PostgreSQL

import (

"github.com/jinzhu/gorm"

_ "github.com/jinzhu/gorm/dialects/postgres"

)

func main() {

db, err := gorm.Open("postgres", "host=myhost port=myport user=gorm dbname=gorm password=mypassword")

defer db.Close()

}

Sqlite3

import (

"github.com/jinzhu/gorm"

_ "github.com/jinzhu/gorm/dialects/sqlite"

)

func main() {

db, err := gorm.Open("sqlite3", "/tmp/gorm.db")

defer db.Close()

}

SQL Server

import (

"github.com/jinzhu/gorm"

_ "github.com/jinzhu/gorm/dialects/mssql"

)

func main() {

db, err := gorm.Open("mssql", "sqlserver://username:password@localhost:1433?database=dbname")

defer db.Close()

}

不支持的数据库

增删改查API

创建

创建记录

user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}

db.NewRecord(user) // => 返回 `true` ,因为主键为空

db.Create(&user)

db.NewRecord(user) // => 在 `user` 之后创建返回 `false`

默认值

你可以通过标签定义字段的默认值,例如:

type Animal struct {

ID int64

Name string `gorm:"default:'galeone'"`

Age int64

}

然后 SQL 会排除那些没有值或者有 零值 的字段,在记录插入数据库之后,gorm 将从数据库中加载这些字段的值。(数据库中为null的字段从默认值中加载)

var animal = Animal{Age: 99, Name: ""}

db.Create(&animal)

// INSERT INTO animals("age") values('99');

// SELECT name from animals WHERE ID=111; // 返回的主键是 111

// animal.Name => 'galeone'

注意 所有包含零值的字段,像 0,'',false 或者其他的 零值 不会被保存到数据库中,但会使用这个字段的默认值。你应该考虑使用指针类型或者其他的值来避免这种情况:

// Use pointer value

type User struct {

gorm.Model

Name string

Age *int `gorm:"default:18"`

}

// Use scanner/valuer

type User struct {

gorm.Model

Name string

Age sql.NullInt64 `gorm:"default:18"`

}

在钩子中设置字段值

如果你想在 BeforeCreate 函数中更新字段的值,应该使用 scope.SetColumn,例如:

func (user *User) BeforeCreate(scope *gorm.Scope) error {

scope.SetColumn("ID", uuid.New())

return nil

}

创建额外选项

// 为插入 SQL 语句添加额外选项

db.Set("gorm:insert_option", "ON CONFLICT").Create(&product)

// INSERT INTO products (name, code) VALUES ("name", "code") ON CONFLICT;

查询

// 获取第一条记录,按主键排序

db.First(&user)

SELECT * FROM users ORDER BY id LIMIT 1;

// 获取一条记录,不指定排序

db.Take(&user)

SELECT * FROM users LIMIT 1;

// 获取最后一条记录,按主键排序

db.Last(&user)

SELECT * FROM users ORDER BY id DESC LIMIT 1;

// 获取所有的记录

db.Find(&users)

SELECT * FROM users;

// 通过主键进行查询 (仅适用于主键是数字类型)

db.First(&user, 10)

SELECT * FROM users WHERE id = 10;

Where

原生sql

/ 获取第一条匹配的记录

db.Where("name = ?", "jinzhu").First(&user)

SELECT * FROM users WHERE name = 'jinzhu' limit 1;

// 获取所有匹配的记录

db.Where("name = ?", "jinzhu").Find(&users)

SELECT * FROM users WHERE name = 'jinzhu';

// <>

db.Where("name <> ?", "jinzhu").Find(&users)

// IN

db.Where("name in (?)", []string{"jinzhu", "jinzhu 2"}).Find(&users)

// LIKE

db.Where("name LIKE ?", "%jin%").Find(&users)

// AND

db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)

// Time

db.Where("updated_at > ?", lastWeek).Find(&users)

// BETWEEN

db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)

Struct & Map

// Struct

db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)

SELECT * FROM users WHERE name = "jinzhu" AND age = 20 LIMIT 1;

// Map

db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)

SELECT * FROM users WHERE name = "jinzhu" AND age = 20;

// 多主键 slice 查询

db.Where([]int64{20, 21, 22}).Find(&users)

SELECT * FROM users WHERE id IN (20, 21, 22);

注意:当通过 struct 进行查询的时候,GORM 将会查询这些字段的非零值, 意味着你的字段包含 0, '', false 或者其他 零值 , 将不会出现在查询语句中, 例如:

db.Where(&User{Name: "jinzhu", Age: 0}).Find(&users)

SELECT * FROM users WHERE name = "jinzhu";

你可以考虑适用指针类型或者 scanner/valuer 来避免这种情况。

// 使用指针类型

type User struct {

gorm.Model

Name string

Age *int

}

// 使用 scanner/valuer

type User struct {

gorm.Model

Name string

Age sql.NullInt64

}

Not

和 Where 查询类似:

db.Not("name", "jinzhu").First(&user)

SELECT * FROM users WHERE name <> "jinzhu" LIMIT 1;

// 不包含

db.Not("name", []string{"jinzhu", "jinzhu 2"}).Find(&users)

SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");

//不在主键 slice 中

db.Not([]int64{1,2,3}).First(&user)

SELECT * FROM users WHERE id NOT IN (1,2,3);

db.Not([]int64{}).First(&user)

SELECT * FROM users ORDER BY ID LIMIT 1;

// 原生 SQL

db.Not("name = ?", "jinzhu").First(&user)

SELECT * FROM users WHERE NOT(name = "jinzhu");

// Struct

db.Not(User{Name: "jinzhu"}).First(&user)

SELECT * FROM users WHERE name <> "jinzhu";

Or

db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)

SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';

// Struct

db.Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2"}).Find(&users)

SELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';

// Map

db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2"}).Find(&users)

SELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';

行内条件查询

和 Where 查询类似。

需要注意的是,当使用链式调用传入行内条件查询时,这些查询不会被传参给后续的中间方法。

// 通过主键进行查询 (仅适用于主键是数字类型)

db.First(&user, 23)

SELECT * FROM users WHERE id = 23 LIMIT 1;

// 非数字类型的主键查询

db.First(&user, "id = ?", "string_primary_key")

SELECT * FROM users WHERE id = 'string_primary_key' LIMIT 1;

// 原生 SQL

db.Find(&user, "name = ?", "jinzhu")

SELECT * FROM users WHERE name = "jinzhu";

db.Find(&users, "name <> ? AND age > ?", "jinzhu", 20)

SELECT * FROM users WHERE name <> "jinzhu" AND age > 20;

// Struct

db.Find(&users, User{Age: 20})

SELECT * FROM users WHERE age = 20;

// Map

db.Find(&users, map[string]interface{}{"age": 20})

SELECT * FROM users WHERE age = 20;

额外的查询选项

// 为查询 SQL 添加额外的选项

db.Set("gorm:query_option", "FOR UPDATE").First(&user, 10)

SELECT * FROM users WHERE id = 10 FOR UPDATE;

FirstOrInit

获取第一条匹配的记录,或者通过给定的条件下初始一条新的记录(仅适用与于 struct 和 map 条件)。

// 未查询到

db.FirstOrInit(&user, User{Name: "non_existing"})

user -> User{Name: "non_existing"}

// 查询到

db.Where(User{Name: "Jinzhu"}).FirstOrInit(&user)

user -> User{Id: 111, Name: "Jinzhu", Age: 20}

db.FirstOrInit(&user, map[string]interface{}{"name": "jinzhu"})

user -> User{Id: 111, Name: "Jinzhu", Age: 20}

Attrs

如果未找到记录,则使用参数初始化 struct

// 未查询到

db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrInit(&user)

SELECT * FROM USERS WHERE name = 'non_existing';

user -> User{Name: "non_existing", Age: 20}

db.Where(User{Name: "non_existing"}).Attrs("age", 20).FirstOrInit(&user)

SELECT * FROM USERS WHERE name = 'non_existing';

user -> User{Name: "non_existing", Age: 20}

// 查询到

db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 30}).FirstOrInit(&user)

SELECT * FROM USERS WHERE name = jinzhu';

user -> User{Id: 111, Name: "Jinzhu", Age: 20}

Assign

无论是否查询到数据,都将参数赋值给 struct

// 未查询到

db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrInit(&user)

user -> User{Name: "non_existing", Age: 20}

// 查询到

db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 30}).FirstOrInit(&user)

SELECT * FROM USERS WHERE name = jinzhu';

user -> User{Id: 111, Name: "Jinzhu", Age: 30}

FirstOrCreate

获取第一条匹配的记录,或者通过给定的条件创建一条记录 (仅适用与于 struct 和 map 条件)。

// 未查询到

db.FirstOrCreate(&user, User{Name: "non_existing"})

INSERT INTO "users" (name) VALUES ("non_existing");

user -> User{Id: 112, Name: "non_existing"}

// 查询到

db.Where(User{Name: "Jinzhu"}).FirstOrCreate(&user)

user -> User{Id: 111, Name: "Jinzhu"}

注:Attrs和Assign用法类似。

这里注意区分FirstOrCreate和FirstOrInit的区别:

FirstOrCreate的创建或更新会触发callback,而FirstOrInit不会。

源码见下图

高级查询

子查询

使用 *gorm.expr 进行子查询

db版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/u010525694/article/details/94294890

站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP