Skip to content
/ go-oorm Public

oorm是一款功能全面的golang数据库操作工具,提供一个漂亮、简洁的链式调用方式来实现与数据库的交互。

License

Notifications You must be signed in to change notification settings

kwinH/go-oorm

Repository files navigation

简介

oorm是一款功能全面的数据库操作工具,提供一个漂亮、简洁的链式调用方式来实现与数据库的交互。

模型定义

	type User struct {
        oorm.Model
        Name      string `db:"index:us|1"`
        Password  string
        Status    int8
        Age       int8
        Sex       int8
        Balance   float64 `db:"decimal:10,2"`
}

连接数据库

mysql

    dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	orm, err = oorm.Open(mysql.Open(dsn), &oorm.Config{})

	if err != nil {
		fmt.Printf("%#v", err.Error())
		panic("连接数据库失败")
	}

连接池

OORM 使用 database/sql 维护连接池

    sqlDB, err := orm.DBPool()
    
    // SetMaxIdleConns 设置空闲连接池中连接的最大数量
    sqlDB.SetMaxIdleConns(10)
    
    // SetMaxOpenConns 设置打开数据库连接的最大数量。
    sqlDB.SetMaxOpenConns(100)
    
    // SetConnMaxLifetime 设置了连接可复用的最大时间。
    sqlDB.SetConnMaxLifetime(time.Hour)

约定

oorm 倾向于约定优于配置 默认情况下,oorm 使用 ID 作为主键,使用结构体名的 蛇形 作为表名,字段名的 蛇形 作为列名,并使用 CreatedAtUpdatedAt 字段追踪创建、更新时间

oorm.Model

oorm 定义一个 oorm.Model 结构体,其包括字段 IDCreatedAtUpdatedAtDeletedAt

您可以将它嵌入到您的结构体中,以包含这几个字段

    type Model struct {
        Id        uint `db:"autoIncrement"`
        CreatedAt time.Time
        UpdatedAt time.Time
        DeletedAt sql.NullTime `db:"index"`
    }

创建/更新时间追踪(微秒、毫秒、秒、Time)

GORM 约定使用 CreatedAtUpdatedAt 追踪创建/更新时间。如果您定义了这种字段,GORM 在创建、更新时会自动填充 当前时间

如果您想要保存 UNIX(毫/微)秒时间戳,而不是 time,您只需简单地将 time.Time 修改为 整数类型 即可,以下即对应关系

int/uint/int32/uint32 类型对应
int64 类型对应毫秒
int64 类型对应微秒

type User struct {
  CreatedAt int  // 在创建时,如果该字段值为零值,则使用当前时间戳秒填充
  UpdatedAt int64       // 在创建时该字段值为零值或者在更新时,使用当前时间戳毫秒数填充
}

字段标签

多个标签用;分割,例如:db:"decimal:10,2;index:us|1"

标签名 说明
field 指定 db 列名
size 定义列数据类型的大小或长度,例如 size: 256
default 定义列的默认值 (可以定义为NULL)
primaryKey 将列定义为主键
autoIncrement 指定列为自动增长(同是也会指定为主键)
decimal 精度 例 db:"decimal:10,2"
comment 迁移时为字段添加注释
raw 原生表达式 例 db:"raw:count(*)"
json 用于自动解析装载json
index 根据参数创建普通索引,多个字段使用相同的名称则创建复合索引
unique 根据参数创建唯一索引,多个字段使用相同的名称则创建复合索引
full 根据参数创建全文索引,多个字段使用相同的名称则创建复合索引

迁移

Auto

AutoMigrate 用于自动迁移您的 schema,保持您的 schema 是最新的。

注意: Auto 会创建表、缺失的外键、列和索引。 出于保护您数据的目的,它可以传第二个参数选择是否更新、传第三个参数选择是否删除(包括字段、属性、注释、索引)。

复合索引需要写成:index:索引名|优先级 ,优先级以小到大排序

	type User struct {
		oorm.Model
		Name      string `db:"index:us|1"`
		Password  string
		Status    int8
		Age       int8
		Sex       int8
		Balance   float64 `db:"decimal:10,2"`
	}


	orm.Migrate.Auto(User{}, true, true)

Migrator 接口

type IMigrator interface {
	TableExist(tableName string) bool
	Create(schema1 *Schema) error
	TableInfo(tableName string) TableInfo

	AddField(TableName string, field *Field) error
	ModifyField(TableName string, field *Field) error
	DropField(TableName string, FiledName string) error

	AddIndex(tableName string, indexType IndexType, indexFields IndexList) error
	DropIndex(indexKey, tableName string) error
	UpdateIndex(schema1 *Schema, schemaKeys IndexList, keys map[string][]string, modify bool, indexType IndexType) (err error)

	Auto(value interface{}, modify, drop bool) error
}

查询构造器

声明

	type User struct {
        oorm.Model
        Name      string `db:"index:us|1"`
        Password  string
        Status    int8
        Age       int8
        Sex       int8
        Balance   float64 `db:"decimal:10,2"`
}

    var users []User
	var user User

获取所有结果

你可以在查询上链式调用更多的约束,最后使用 Get 方法获取结果

orm.Get(&users)

查询单个结果

orm.Where("user_name","kwinwong").First(&user)

根据主键检索

orm.Where("user_name","kwinwong").Find(&user,1)

聚合查询

查询构造器还提供了各种聚合方法,比如 countmaxminavg,还有 sum。你可以在构造查询后调用任何方法:

// SELECT max(`id`)  FROM `user` []
res,err := orm.Table("user").Max("id")

// SELECT min(`id`) FROM `user` []
res,err := orm.Table("user").Mix("id")

// SELECT count(*) as `c` FROM `user` []
res,err := orm.Table("user").Count()

Group分组查询的时候,会被当做子查询

// SELECT COUNT(*) FROM (SELECT `id` FROM `user` GROUP BY `status`) as `tmp1`
res,err := orm.Table("user").Group("status").Select("id").Count()

如果需要分组查询:

    type User struct {
    Status int8
    C      int `db:"raw:count(*)"`
    }
    
    var users []User
    // SELECT `status`,count(*) FROM `user` GROUP BY `status`
    orm.Group("status").Get(&users)

Select

查询字段 默认查询所有字段

支持多个参数,单个参数,切片方式传值

// SELECT `id`,`name` as `n` FROM `user` []
err := orm.Select("id", "name as n").Get(&users)

err := orm.Select("id,name n").Get(&users)

err := orm.Select([]string{"id", "name n"}).Get(&users)

Omit

忽略字段

// SELECT `id`,`created_at`,`updated_at`,`deleted_at`,`name`,`password`,`status`,`age`,`sex`,`balance` FROM `user` WHERE `user`.`deleted_at` IS NULL []
err := orm.Omit("age", "sex").Get(&users)

原生表达式

有时候你可能需要在查询中使用原生表达式。你可以使用 sqlBuilder.Raw 创建一个原生表达式:

原生查询

	type User struct {
		Sex int8
		C      int
	}

	var u []User
	err := orm.Raw("SELECT sex,count(*) c from `user` group by sex having c>?", 100).Get(&u)

原生执行

res, err := orm.Exec("UPDATE `user` SET `status`=1 WHERE id=?", 1)

原生字段

// SELECT DISTINCT mobile FROM `user` []
err := orm.Select(sqlBuilder.Raw("DISTINCT mobile")).Get(&users)

原生条件

// SELECT * FROM `user` WHERE price > IF(state = 'TX', 200, 100) []
err := orm.Where(sqlBuilder.Raw("price > IF(state = 'TX', 200, 100)")).Get(&users)

Table

指定查询表名

//SELECT * FROM `users`
orm.Table("users").Get(&users)

子查询

// SELECT * FROM (SELECT * FROM (SELECT `sex`,count(*) as `c` FROM m_users GROUP BY `sex`) as `tmp2`) as `tmp1` []
err := orm.Table(func (m *sqlBuilder.Builder) {
m.Table(func (m *sqlBuilder.Builder) {
m.Table("m_users").Select("sex", "count(*) as c").Group("sex")
})
}).Get(&users)

Where

简单where语句

在构造 where 查询实例中,你可以使用 where 方法。调用 where 最基本的方式是需要传递三个参数:第一个参数是列名,第二个参数是任意一个数据库系统支持的运算符,第三个是该列要比较的值。

// SELECT `id`,`name` FROM `users` WHERE  `id` < ?  [100]
err := orm.Where("id", "<", 100).Get(&users)

为了方便,如果你只是简单比较列值和给定数值是否相等,可以将数值直接作为 where 方法的第二个参数:

// SELECT `id`,`name` FROM `users` WHERE  `id` = ? [1]
err := orm.Where("id", 1).Get(&users)

OrWhere语句

orWhere 方法和 where 方法接收的参数一样:

// SELECT * FROM `user` WHERE  `id` = ? OR  `name` like ? [1 %q%]
err := orm.Where("id", 1).OrWhere("name", "like", "%q%").Get(&users)

WhereBetween / WhereNotIn / WhereNotBetween / OrWhereNotBetween

WhereBetween 方法验证字段值是否在给定的两个值之间:

可以传一个数组,也可以传2个值

// SELECT * FROM `user` WHERE `sex` = ? AND `attribute` BETWEEN ? AND ? [1 2 3]
err := orm.Where("sex", 1).WhereBetween("attribute", 2, 3).Get(&users)

// SELECT * FROM `user` WHERE `sex` = ? OR `attribute` BETWEEN ? AND ? [1 2 3]
err := orm.Where("sex", 1).OrWhereBetween("attribute", []int{2, 3}).Get(&users)

WhereNotBetween 方法用于验证字段值是否在给定的两个值之外:

可以传一个数组,也可以传2个值

// SELECT * FROM `user` WHERE `sex` = ? AND `attribute` NOT BETWEEN ? AND ? [1 2 3]
err := orm.Where("sex", 1).WhereNotBetween("attribute", 2, 3).Get(&users)

// SELECT * FROM `user` WHERE `sex` = ? OR `attribute` NOT BETWEEN ? AND ? [1 2 3]
err := orm.Where("sex", 1).OrWhereNotBetween("attribute", []int{2, 3}).Get(&users)

WhereIn / WhereNotIn / OrWhereIn / OrWhereNotIn

WhereIn 方法验证给定列的值是否包含在给定数组中:

可以传一个数组,也可以传多个值

// SELECT * FROM `user` WHERE `sex` = ? AND `id` IN (?,?) [1 100 200]
err := orm.Where("sex", 1).WhereIn("id", 100, 200).Get(&users)

// SELECT * FROM `user` WHERE `sex` = ? OR `id` IN (?,?) [1 100 200]
err := orm.Where("sex", 1).OrWhereIn("id", []int{100, 200}).Get(&users)

WhereNotIn 方法验证给定列的值是否不存在给定的数组中:

// SELECT * FROM `user` WHERE `sex` = ? AND `id` NOT IN (?,?) [1 100 200]
err := orm.Where("sex", 1).WhereNotIn("id", []int{100, 200}).Get(&users)

// SELECT * FROM `user` WHERE `sex` = ? OR `id` NOT IN (?,?) [1 100 200]
err := orm.Where("sex", 1).OrWhereNotIn("id", []int{100, 200}).Get(&users)

WhereNull / WhereNotNull / OrWhereNull / OrWhereNotNull

WhereNull 方法验证指定的字段必须是 NULL:

// SELECT * FROM `user` WHERE `sex` = ? AND `deleted_at` IS NULL [1]
err := orm.Where("sex", 1).WhereNull("deleted_at").Get(&users)

// SELECT * FROM `user` WHERE `sex` = ? OR `deleted_at` IS NULL [1]
err := orm.Where("sex", 1).OrWhereNull("deleted_at").Get(&users)

WhereNotNull 方法验证指定的字段肯定不是 NULL:

// SELECT * FROM `user` WHERE `sex` = ? AND `deleted_at` IS NOT NULL [1]
err := orm.Where("sex", 1).WhereNotNull("deleted_at").Get(&users)

// SELECT * FROM `user` WHERE `sex` = ? OR `deleted_at` IS NOT NULL [1]
err := orm.Where("sex", 1).OrWhereNotNull("deleted_at").Get(&users)

分组查询

如果需要在括号内对 or 条件进行分组,将闭包作为 orWhere 方法的第一个参数也是可以的:

// SELECT `id` FROM `user` WHERE  `id` <> ? OR  ( `age` > ? AND  `name` like ?) [1 18 %q%]
sql, bindings := orm.Where("id", "<>", 1).OrWhere(func (m *sqlBuilder.Builder) {
m.Where("age", ">", 18).
Where("name", "like", "%q%")
}).Get(&users)

子查询 Where 语句

// SELECT * FROM `user` WHERE  `id` <> ? AND  `id` in (SELECT `id` FROM `user_old` WHERE  `age` > ? AND  `name` like ?) [1 18 %q%]
err := orm.Where("id", "<>", 1).WhereIn("id", func (m *sqlBuilder.Builder) {
m.Select("id").
Table("user_old").
Where("age", ">", 18).
Where("name", "like", "%q%")
}).Get(&users)

Order

Order方法允许你通过给定字段对结果集进行排序。 order 的第一个参数应该是你希望排序的字段,第二个参数控制排序的方向,可以是 ascdesc,也可以省略,默认是desc

// SELECT `id`,`name` FROM `user` ORDER BY `id` DESC []
err := orm.Select("id", "name").Order("id", "desc").Get(&users)

如果你需要使用多个字段进行排序,你可以多次调用 Order

// SELECT `id`,`name` FROM `user` ORDER BY `id` DESC,`age` ASC []
err := orm.Select("id", "name").Order("id").Order("age", "asc").Get(&users)

groupBy / Having

groupBy 和 having 方法用于将结果分组。 having 方法的使用与 where 方法十分相似:

// SELECT `age`,count( * ) as `c` FROM `user` GROUP BY `age` HAVING  `c` > ? [10]
err := orm.Select("age", "count(*) as c").Group("age").Having("c", ">", 10).Get(&users)

// SELECT `age`,`sex`,count( * ) as `c` FROM `user` GROUP BY `age`,`sex` HAVING  `c` > ? [10]
err := orm.Select("age", 'sex', "count(*) as c").Group("age", "sex").Having("c", ">", 10).Get(&users)

Limit

// SELECT `id`,`name` FROM `user` LIMIT 10 []
err := orm.Select("id", "name").Limit(10).Get(&users)

// SELECT `id`,`name` FROM `user` LIMIT 1,10 []
err := orm.Select("id", "name").Limit(1, 10).Get(&users)

Page

//SELECT `id`,`name` FROM `user` LIMIT 0,10 []
err := orm.Select("id", "name").Page(1, 10).Get(&users)

Joins

Inner Join 语句

查询构造器也可以编写 join 方法。若要执行基本的「内链接」,你可以在查询构造器实例上使用 Join 方法。传递给 Join 方法的第一个参数是你需要连接的表的名称,第二个参数是指定连接的字段约束,而其他的则是绑定参数。你还可以在单个查询中连接多个数据表:

// SELECT `id`,`name` FROM `user` INNER JOIN `order` as `o` o.user_id=u.user_id and o.type=? INNER JOIN `contacts` as `c` c.user_id=u.user_id [1]
err := orm.Table("user u").Select("id", "name").
Join("order o", "o.user_id=u.user_id and o.type=?", 1).
Join("contacts c", "c.user_id=u.user_id").
Get(&users)

Left Join / Right Join 语句

如果你想使用 「左连接」或者 「右连接」代替「内连接」 ,可以使用 LeftJoin 或者 RightJoin 方法。这两个方法与 Join 方法用法相同:

// SELECT `id`,`name` FROM `user` RIGHT JOIN `contacts` as `c` c.user_id=u.user_id []
err := orm.Table("user u").Select("id", "name").
LeftJoin("contacts c", "c.user_id=u.user_id").
Get(&users)

// SELECT `id`,`name` FROM `user` LEFT JOIN `contacts` as `c` c.user_id=u.user_id []
err := orm.Table("user u").Select("id", "name").
RightJoin("contacts c", "c.user_id=u.user_id").
Get(&users)

关联子查询

// SELECT `id`,`name` FROM `user` as `u` INNER JOIN (SELECT * FROM `contacts` WHERE `id` > ?) as `tmp1` tmp1.user_id=u.user_id [100]
err := orm.Table("user u").Select("id", "name").
Join(func(b *sqlBuilder.Builder) {
b.Table("contacts").Where("id", ">", 100)
}, "tmp1.user_id=u.user_id").
Get(&users)

模型关联

可以使用 with 方法指定想要预加载的关联

一对一

一对一是最基本的关联关系。例如,一个 User 模型可能关联一个 Contact 模型。为了定义这个关联,我们要在 User 模型中定义一个 Contact 模型。

声明

type Contact struct{
	oorm.Model
	UserId uint
	Mobile string
	Email string
}

type User struct {
	oorm.Model
	UserName string
	Password string
	Nickname string
	Status   string
	Avatar  string
	Contact  Contact
}

检索

func GetUser(db *oorm.DB) (*User, error) {
	var user = &User{}

// SELECT `id`,`created_at`,`updated_at`,`deleted_at`,`user_name`,`password`,`nickname`,`status`,`avatar` FROM `user` WHERE `id` = "1" LIMIT 1
// SELECT `id`,`created_at`,`updated_at`,`deleted_at`,`user_id`,`uid`,`mobile`,`email` FROM `contact` WHERE `user_id` in ("1")
	err := db.With("Contact").Find(user, 1)

	if err != nil {
		return nil, err
	}
	return user, err
}

oorm 会基于模型名决定外键名称。在这种情况下,会自动假设 Contact 模型有一个 UserId 外键。如果你想覆盖这个约定,标签 foreignKey 来更改它:

type User struct {
    oorm.Model
    UserName string
    Password string
    Nickname string
    Status   string
    Avatar   string
    Contact  Contact `db:"foreignKey:Uid"`
}

type Contact struct {
    oorm.Model
    Uid    uint
    Mobile string
    Email  string
}
func GetUser(db *oorm.DB) (*User, error) {
	var user = &User{}

// SELECT `id`,`created_at`,`updated_at`,`deleted_at`,`user_name`,`password`,`nickname`,`status`,`avatar` FROM `user` WHERE `id` = "1" LIMIT 1
// SELECT `id`,`created_at`,`updated_at`,`deleted_at`,`user_id`,`uid`,`mobile`,`email` FROM `contact` WHERE `uid` in ("1")
	err := db.With("Contact").Find(user, 1)

	if err != nil {
		return nil, err
	}
	return user, err
}

一对一(反向)

我们已经能从 User 模型访问到 Contact 模型了。现在,让我们再在 Contact 模型上定义一个关联,这个关联能让我们访问到拥有该ContactUser 模型

以下声明表示拿Contact模型的UserId字段去查询User模型下的Id字段

声明

type Contact struct {
    oorm.Model
    UserId uint
    Mobile string
    Email  string
    User   User `db:"localKey:UserId;foreignKey:Id"`
}

type User struct {
    oorm.Model
    UserName string
    Password string
    Nickname string
    Status   string
    Avatar   string
}

检索

func GetUser(db *oorm.DB) (*Contact, error) {
    var contact = &Contact{}

// SELECT `id`,`created_at`,`updated_at`,`deleted_at`,`user_id`,`mobile`,`email` FROM `contact` WHERE `id` = "2" LIMIT 1
// SELECT `id`,`created_at`,`updated_at`,`deleted_at`,`user_name`,`password`,`nickname`,`status`,`avatar` FROM `user` WHERE `id` in ("1")
	err := db.With("Contact").Find(contact, 2)

	if err != nil {
		return nil, err
	}
	return contact, err
}

一对多

一对一是最基本的关联关系。例如,一个 User 模型可能关联多个 Contact 模型。为了定义这个关联,我们要在 User 模型中定义一个数组 Contact 模型。

声明

type Contact struct{
	oorm.Model
	UserId uint
	Mobile string
	Email string
}

type User struct {
	oorm.Model
	UserName string
	Password string
	Nickname string
	Status   string
	Avatar  string
	Contact  []Contact
}

检索

func GetUser(db *oorm.DB) (*User, error) {
	var user = &User{}

// SELECT `id`,`created_at`,`updated_at`,`deleted_at`,`user_name`,`password`,`nickname`,`status`,`avatar` FROM `user` WHERE `id` = "1" LIMIT 1
// SELECT `id`,`created_at`,`updated_at`,`deleted_at`,`user_id`,`uid`,`mobile`,`email` FROM `contact` WHERE `user_id` in ("1")
	err := db.With("Contact").Find(user, 1)

	if err != nil {
		return nil, err
	}
	return user, err
}

oorm 会基于模型名决定外键名称。在这种情况下,会自动假设 Contact 模型有一个 UserId 外键。如果你想覆盖这个约定,标签 foreignKey 来更改它:

type User struct {
    oorm.Model
    UserName string
    Password string
    Nickname string
    Status   string
    Avatar   string
    Contact  []Contact `db:"foreignKey:Uid"`
}

type Contact struct {
    oorm.Model
    Uid    uint
    Mobile string
    Email  string
}
func GetUser(db *oorm.DB) (*User, error) {
	var user = &User{}

// SELECT `id`,`created_at`,`updated_at`,`deleted_at`,`user_name`,`password`,`nickname`,`status`,`avatar` FROM `user` WHERE `id` = "1" LIMIT 1
// SELECT `id`,`created_at`,`updated_at`,`deleted_at`,`user_id`,`uid`,`mobile`,`email` FROM `contact` WHERE `uid` in ("1")
	err := db.With("Contact").Find(user, 1)

	if err != nil {
		return nil, err
	}
	return user, err
}

插入 & 更新关联模型

With指定需要更新的关联模型

如果不在事务中,则系统会创建一个事务,统一提交

声明

	type Contact struct {
		oorm.Model
		UserId uint
		Mobile string
	}

	type User struct {
		oorm.Model
		UserName string
		Contact  []Contact
	}

新增

func CreatreUser(db *oorm.DB) (*User, error) {
	var user = &User{
		UserName: "kwinwong",
		Contact: []Contact{{
			Mobile: "13758665977",
		}, {
			Mobile: "13589217699",
		},
		},
	}

// INSERT INTO `user` (`user_name`,`created_at`,`updated_at`) VALUES("kwinwong","2022-10-24 17:25:47.806","2022-10-24 17:25:47.806")
// INSERT INTO `contact` (`user_id`,`mobile`,`created_at`,`updated_at`) VALUES("1","13758665977","2022-10-24 17:25:47.811","2022-10-24 17:25:47.811"),("1","13589217699","2022-10-24 17:25:47.811","2022-10-24 17:25:47.811")		
    res, err := db.With("Contact").Create(user)
    if err != nil {
        return nil, err
    }
	
    return user, err
}

新增

查询构造器还提供了 Create 方法用于插新增记录到数据库中。

创建Model

	user := User{
		UserName: "kwin",
		Status:   1,
	}

	res, err := orm.Create(&user)

用指定的字段创建记录

创建传递的选定字段

	res, err := orm.Select("user_name,status").Create(&users)

创建忽略传递的选定字段

	res, err := orm.Omit("user_name,status").Create(&users)

创建忽略传递的空值字段

	res, err := orm.OmitEmpty().Create(&users)

批量插入

可以传递给Create一个slice,或则传递多个Model

	users := []User{
		{
			UserName: "kwin",
		},
		{
			UserName: "kwin2",
		},
	}

	_, err := orm.Create(&users)
	user1 := User{
		UserName: "kwin",
		Status:   1,
	}

    user2 := User{
        UserName: "kwin2",
        Status:   1,
    }
	_, err := orm.Create(&user1,&user2)

根据Map创建

// INSERT INTO `user` (`name`,`age`) VALUES(?,?) [张三 18]
sql, bindings, err = orm.Create(map[string]interface{}{
"name": "张三",
"age":  18,
})

你甚至可以传递多个map给 Create 方法,依次将多个记录插入到表中:

注意:多个map参数要一致,以第一个为准,否则会省略后面不一致的map

// INSERT INTO `user` (`name`,`age`) VALUES(?,?),(?,?) [张三 18 李四 30]
sql, bindings, err = orm.Create(map[string]interface{}{
"name": "张三",
"age":  18,
}, map[string]interface{}{
"name": "李四",
"age":  30,
})

更新

根据主键更新

当没有其他条件时,以主键为条件,当指定了其他条件,则主键不参与条件

	user := User{
		Model: Model{
			Id: 2,
		},
		UserName: "kwin",
		Password: "123456",
		Nickname: "kwin",
		Status:   1,
	}
    
	// UPDATE `user` SET `password`="123456",`nickname`="kwin",`status`=1,`avatar`="",`updated_at`="2022-10-28 11:17:53.303",`user_name`="kwin" WHERE `id` = 2
	res, err := orm.Update(&user)

根据条件更新

	user := User{
		UserName: "kwin",
		Password: "123456",
		Nickname: "kwin",
		Status:   1,
	}
    
	// UPDATE `user` SET `password`="123456",`nickname`="kwin",`status`=1,`avatar`="",`updated_at`="2022-10-28 11:17:53.303",`user_name`="kwin" WHERE `user_name` = "kwin"
	res, err := orm.Where("user_name","kwin").Update(&user)

用指定的字段跟新记录

更新传递的选定字段

	res, err := orm.Select("user_name,status").Update(&user)

更新忽略传递的选定字段

	res, err := orm.Omit("user_name,status").Update(&user)

更新忽略传递的空值字段

	res, err := orm.OmitEmpty().Update(&user)

根据Map更新

// UPDATE `user` SET `name`=?,`age`=? WHERE `id` = ? [test 18 1]
err := orm.Table("user").Where("id", 1).Update(map[string]interface{}{
"name": "test",
"age":  18,
})

删除

根据主键记录

// user.Id=1 不带条件 则主键不能为空
// UPDATE `user` SET `deleted_at`=? WHERE `id` = ? ["2022-10-26 17:19:04.981",1]
affected,err := orm.Delete(&user)

条件删除

当带有其他条件,则主键不引用

// UPDATE `user` SET `deleted_at`=? WHERE `id` <> ? ["2022-10-26 17:19:04.981",100]
affected,err := orm.Where("id","<",100).Delete(&user)

软删除

如果您的模型包含了一个 oorm.DeletedAt 字段(oorm.Model 已经包含了该字段),它将自动获得软删除的能力!

拥有软删除能力的模型调用 Delete 时,记录不会从数据库中被真正删除。但 oorm 会将 DeletedAt 置为当前时间, 并且你不能再通过普通的查询方法找到该记录。

查找被软删除的记录

您可以使用 WithDelete 找到被软删除的记录

orm.WithDelete().Get(&users)

强制删除

当调用Delete方法传了第二个参数为true时,则强制删除

// delete from `user` WHERE `id` < ? [100]
affected,err := orm.Where("id","<",100).Delete(&user,true)

数据库事务

想要在数据库事务中运行一系列操作,你可以使用 oormTransaction 方法。如果在事务的闭包中出现了异常,事务将会自动回滚。如果闭包执行成功,事务将会自动提交。在使用 Transaction 方法时不需要手动回滚或提交:

	orm.Transaction(func(db *DB) (err error) {
        user := User{
        UserName: "test",
        }
        
        _, err = d.Select("user_name").Create(&user)
        
        if err != nil {
            return err
        }
        
        _, err = orm.Where("user_name", "test").Delete(&user)
        
        if err != nil {
            return err
        }
        
        return nil
	})

手动执行事务

如果你想要手动处理事务并完全控制回滚和提交,可以使用 oorm 提供的 Begin 方法:

在事务中所有的操作都要用Begin返回的*oorm.DB对象去操作,包括回滚和提交

db, err := d.Begin()

你可以通过 RollBack 方法回滚事务:

 db.Rollback()

最后,你可以通过 Commit 方法提交事务:

db.Commit()

钩子

访问器 / 修改器

定义一个访问器

若要定义一个访问器, 则需在模型上创建一个 GetAttr 方法

var _ IGetAttr = (*User)(nil)

func (u *User) GetAttr() {
	u.UserName = strings.ToUpper(u.UserName)
}

定义一个修改器

若要定义一个访问器, 则需在模型上创建一个 GetAttr 方法

var _ ISetAttr = (*User)(nil)

func (u *User) SetAttr() {
    if u.Password != "" {
        u.Password = fmt.Sprintf("%x", md5.Sum([]byte(u.Password)))
    }
}

JSON自动转化

当标签中有 json,则系统会自动解析、装载

type User struct {
	oorm.Model
	Extend   map[string]interface{} `db:"json"`
}	

查询模型

// IBeforeQuery 查询前钩子
type IBeforeQuery interface {
	BeforeQuery(*DB) error
}

// IAfterQuery 查询后钩子
type IAfterQuery interface {
	AfterQuery(*DB) error
}

创建模型

// IBeforeCreate 创建前钩子
type IBeforeCreate interface {
	BeforeCreate(*DB) error
}

// IAfterCreate 查询后钩子
type IAfterCreate interface {
	AfterCreate(*DB) error
}

修改模型

// IBeforeUpdate 修改前钩子
type IBeforeUpdate interface {
	BeforeUpdate(*DB) error
}

// IAfterUpdate 修改后钩子
type IAfterUpdate interface {
	AfterUpdate(*DB) error
}

删除模型

// IBeforeDelete 删除前钩子
type IBeforeDelete interface {
	BeforeDelete(*DB) error
}

// IAfterDelete 删除后钩子
type IAfterDelete interface {
	AfterDelete(*DB) error
}

About

oorm是一款功能全面的golang数据库操作工具,提供一个漂亮、简洁的链式调用方式来实现与数据库的交互。

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages