gorm常用

2024-03-11 21:28
文章标签 常用 gorm

本文主要是介绍gorm常用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一.CURD相关

创建记录

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

result := db.Create(&user) // 通过数据的指针来创建

user.ID // 返回插入数据的主键

result.Error // 返回

error result.RowsAffected // 返回插入记录的条数

我们还可以使用 Create() 创建多项记录:

users := []*User{

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

   User{Name: "Jackson", Age: 19, Birthday:  time.Now()},

}

result := db.Create(users) // 传递切片以插入多行数据

result.Error // 返回

error result.RowsAffected // 返回插入记录的条数

NOTE 你无法向 ‘create’ 传递结构体,所以你应该传入数据的指针.

用指定的字段创建记录

创建记录并为指定字段赋值。

db.Select("Name", "Age", "CreatedAt").Create(&user)

// INSERT INTO `users` (`name`,`age`,`created_at`) VALUES ("jinzhu", 18, "2020-07-04 11:05:21.775")

创建记录并忽略传递给 ‘Omit’ 的字段值

db.Omit("Name", "Age", "CreatedAt").Create(&user)

// INSERT INTO `users` (`birthday`,`updated_at`) VALUES ("2020-01-01 00:00:00.000", "2020-07-04 11:05:21.775")

批量插入

要高效地插入大量记录,请将切片传递给Create方法。 GORM 将生成一条 SQL 来插入所有数据,以返回所有主键值,并触发 Hook 方法。 当这些记录可以被分割成多个批次时,GORM会开启一个事务</0>来处理它们。

var users = []User{{Name: "jinzhu1"}, {Name: "jinzhu2"}, {Name: "jinzhu3"}}

db.Create(&users)

for _, user := range users {

    user.ID // 1,2,3

}

你可以通过db.CreateInBatches方法来指定批量插入的批次大小

var users = []User{{Name: "jinzhu_1"}, ...., {Name: "jinzhu_10000"}} // batch size 100 db.CreateInBatches(users, 100)

创建钩子

GROM允许用户通过实现这些接口 BeforeSaveBeforeCreateAfterSaveAfterCreate来自定义钩子。 这些钩子方法会在创建一条记录时被调用,关于钩子的生命周期请参阅Hooks。

注意 在 GORM 中保存、删除操作会默认运行在事务上, 因此在事务完成之前该事务中所作的更改是不可见的,如果您的钩子返回了任何错误,则修改将被回滚

Hook (对象生命周期)是在创建、查询、更新、删除等操作之前、之后调用的函数。

如果您已经为模型定义了指定的方法,它会在创建、更新、查询、删除时自动被调用。如果任何回调返回错误,GORM 将停止后续的操作并回滚事务。

钩子方法的函数签名应该是 func(*gorm.DB) error

func (u *User) BeforeCreate(tx *gorm.DB) (err error) {

   u.UUID = uuid.New()

  if u.Role == "admin" {

    return errors.New("invalid role")

   }

   return

}

如果你想跳过Hooks方法,可以使用SkipHooks会话模式,例子如下

DB.Session(&gorm.Session{SkipHooks: true}).Create(&user) DB.Session(&gorm.Session{SkipHooks: true}).Create(&users) DB.Session(&gorm.Session{SkipHooks: true}).CreateInBatches(users, 100)

根据 Map 创建

GORM支持通过 map[string]interface{} 与 []map[string]interface{}{}来创建记录。

db.Model(&User{}).Create(map[string]interface{}{ "Name": "jinzhu", "Age": 18, })

// batch insert from `[]map[string]interface{}{}`

db.Model(&User{}).Create([]map[string]interface{}{

     {"Name": "jinzhu_1", "Age": 18}, {"Name": "jinzhu_2", "Age": 20},

})

注意当使用map来创建时,钩子方法不会执行,关联不会被保存且不会回写主键。

高级选项

关联创建

创建关联数据时,如果关联值非零,这些关联会被upsert,并且它们的Hooks方法也会被调用。

type CreditCard struct {

   gorm.Model

   Number string

    UserID uint

}

type User struct {

   gorm.Model

   Name string

   CreditCard CreditCard

}

db.Create(&User{ Name: "jinzhu", CreditCard: CreditCard{Number: "411111111111"} })

// INSERT INTO `users` ... // INSERT INTO `credit_cards` ...

你可以通过SelectOmit方法来跳过关联更新,示例如下:

db.Omit("CreditCard").Create(&user) // skip all associations db.Omit(clause.Associations).Create(&user)

默认值

你可以通过结构体Tag default来定义字段的默认值,示例如下:

type User struct { ID int64 Name string `gorm:"default:galeone"` Age int64 `gorm:"default:18"` }

这些默认值会被当作结构体字段的零值插入到数据库中

注意,当结构体的字段默认值是零值的时候比如 0''false,这些字段值将不会被保存到数据库中,你可以使用指针类型或者Scanner/Valuer来避免这种情况。

type User struct {

  gorm.Model

  Name string

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

  Active sql.NullBool `gorm:"default:true"`

}

注意,若要让字段在数据库中拥有默认值则必须使用defaultTag来为结构体字段设置默认值。如果想要在数据库迁移的时候跳过默认值,可以使用 default:(-),示例如下:

type User struct {

   ID string `gorm:"default:uuid_generate_v3()"` // db func

  FirstName string

  LastName string

  Age uint8

  FullName string `gorm:"->;type:GENERATED ALWAYS AS (concat(firstname,' ',lastname));default:(-);"`

}

注意 SQLite 不支持批量插入的时候使用默认值。 前往 SQLite Insert stmt了解。 下面是一个使用案例:

type Pet struct {

 Name string

 `gorm:"default:cat"`

} // 在SqlLite中,这是不允许的, 所以GORM会通过构建错误的SQL来返回错误: // INSERT INTO `pets` (`name`) VALUES ("dog"),(DEFAULT) RETURNING `name` db.Create(&[]Pet{{Name: "dog"}, {}})

一个可行的替代方案是通过钩子方法来设置默认字段

func (p *Pet) BeforeCreate(tx *gorm.DB) (err error) { if p.Name == "" { p.Name = "cat" } }

查询 检索单个对象

GORM 提供了 FirstTakeLast 方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1 条件,且没有找到记录时,它会返回 ErrRecordNotFound 错误

  • // 获取第一条记录(主键升序)
    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;

    result := db.First(&user)
    result.RowsAffected // 返回找到的记录数
    result.Error // returns error or nil

    // 检查 ErrRecordNotFound 错误
    errors.Is(result.Error, gorm.ErrRecordNotFound)

如果你想避免ErrRecordNotFound错误,你可以使用Find,比如

db.Limit(1).Find(&user)Find方法可以接受struct和slice的数据。

对单个对象使用Find而不带limit,db.Find(&user)将会查询整个表并且只返回第一个对象,这是性能不高并且不确定的。

First and Last 方法会按主键排序找到第一条记录和最后一条记录 (分别)。 只有在目标 struct 是指针或者通过 db.Model() 指定 model 时,该方法才有效。 此外,如果相关 model 没有定义主键,那么将按 model 的第一个字段进行排序。 例如:

--javascripttypescriptbashsqljsonhtmlcssccppjavarubypythongorustmarkdown

var user User
var users []User// works because destination struct is passed in
db.First(&user)
// SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1// works because model is specified using `db.Model()`
result := map[string]interface{}{}
db.Model(&User{}).First(&result)
// SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1// doesn't work
result := map[string]interface{}{}
db.Table("users").First(&result)// works with Take
result := map[string]interface{}{}
db.Table("users").Take(&result)// no primary key defined, results will be ordered by first field (i.e., `Code`)
type Language struct {Code stringName string
}
db.First(&Language{})
// SELECT * FROM `languages` ORDER BY `languages`.`code` LIMIT 1

检索全部对象

// 获取所有记录 result := db.Find(&users) // SELECT * FROM users; result.RowsAffected // 返回找到的记录数,等于 `len(users)` result.Error // 返回错误

条件

String 条件

// 获取第一条匹配记录
db.Where( "name = ?" , "jinzhu" ).First(&user)
// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;

// 获取所有匹配的记录
db.Where( "name <> ?" , "jinzhu" ).Find(&users)
// SELECT * FROM users WHERE name <> 'jinzhu';

// IN
db.Where( "name IN ?" , [] string { "jinzhu" , "jinzhu 2" }).Find(&users)
// SELECT * FROM 用户 WHERE name IN ('jinzhu','jinzhu 2' );

// LIKE
db.Where( "name LIKE ?" , "%jin%" ).Find(&users)
// SELECT * FROM 用户 WHERE name LIKE '%jin%';

// AND
db.Where( "name = ? AND Age >= ?" , "jinzhu" , "22" ).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' AND Age >= 22;

// 时间
db.Where( "updated_at > ?" , lastWeek).Find(&users)
// SELECT * FROM 用户 WHERE Updated_at > '2000-01-01 00:00:00';

// BETWEEN
db.Where( "created_at BETWEEN ? AND ?" , lastWeek, Today).Find(&users)
// SELECT * FROM 用户 WHEREcreated_at BETWEEN '2000-01-01 00:00:00' AND '2000-01 -08 00:00:00';

如果对象设置了主键,条件查询将不会覆盖主键的值,而是用 And 连接条件。 例如:

var user = User{

 ID: 10

}

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

// SELECT * FROM users WHERE id = 10 and id = 20 ORDER BY id ASC LIMIT 1

这个查询将会给出record not found错误 所以,在你想要使用例如 user 这样的变量从数据库中获取新值前,需要将例如 id 这样的主键设置为nil。

Struct & Map 条件

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

// SELECT * FROM users WHERE name = "jinzhu" AND Age = 20 ORDER BY id LIMIT 1;

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

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

// 主键切片

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

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

**注意:**当使用 struct 进行查询时,GORM 只会查询非零字段,这意味着如果您的字段值为0''false其他零值,则不会用于构建查询条件,例如:

db.Where(&User{姓名: "jinzhu" , 年龄: 0 }).Find(&users)

// SELECT * FROM 用户 WHERE name = "jinzhu";

要在查询条件中包含零值,可以使用映射,它将包含所有键值作为查询条件,例如:

db.Where( map [ string ] interface {}{ "Name" : "jinzhu" , "Age" : 0 }).Find(&users)

// SELECT * FROM users WHERE name = "jinzhu" AND Age = 0;

这篇关于gorm常用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/799128

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

常用的jdk下载地址

jdk下载地址 安装方式可以看之前的博客: mac安装jdk oracle 版本:https://www.oracle.com/java/technologies/downloads/ Eclipse Temurin版本:https://adoptium.net/zh-CN/temurin/releases/ 阿里版本: github:https://github.com/

30常用 Maven 命令

Maven 是一个强大的项目管理和构建工具,它广泛用于 Java 项目的依赖管理、构建流程和插件集成。Maven 的命令行工具提供了大量的命令来帮助开发人员管理项目的生命周期、依赖和插件。以下是 常用 Maven 命令的使用场景及其详细解释。 1. mvn clean 使用场景:清理项目的生成目录,通常用于删除项目中自动生成的文件(如 target/ 目录)。共性规律:清理操作

019、JOptionPane类的常用静态方法详解

目录 JOptionPane类的常用静态方法详解 1. showInputDialog()方法 1.1基本用法 1.2带有默认值的输入框 1.3带有选项的输入对话框 1.4自定义图标的输入对话框 2. showConfirmDialog()方法 2.1基本用法 2.2自定义按钮和图标 2.3带有自定义组件的确认对话框 3. showMessageDialog()方法 3.1

工作常用指令与快捷键

Git提交代码 git fetch  git add .  git commit -m “desc”  git pull  git push Git查看当前分支 git symbolic-ref --short -q HEAD Git创建新的分支并切换 git checkout -b XXXXXXXXXXXXXX git push origin XXXXXXXXXXXXXX

java常用面试题-基础知识分享

什么是Java? Java是一种高级编程语言,旨在提供跨平台的解决方案。它是一种面向对象的语言,具有简单、结构化、可移植、可靠、安全等特点。 Java的主要特点是什么? Java的主要特点包括: 简单性:Java的语法相对简单,易于学习和使用。面向对象:Java是一种完全面向对象的语言,支持封装、继承和多态。跨平台性:Java的程序可以在不同的操作系统上运行,称为"Write once,

nginx介绍及常用功能

什么是nginx nginx跟Apache一样,是一个web服务器(网站服务器),通过HTTP协议提供各种网络服务。 Apache:重量级的,不支持高并发的服务器。在Apache上运行数以万计的并发访问,会导致服务器消耗大量内存。操作系统对其进行进程或线程间的切换也消耗了大量的CPU资源,导致HTTP请求的平均响应速度降低。这些都决定了Apache不可能成为高性能WEB服务器  nginx:

常用排序算法分析

1. 插入排序 1.1 性能分析 时间复杂度O(n^2), 空间复杂度O(1) 排序时间与输入有关:输入的元素个数;元素已排序的程度。 最佳情况,输入数组是已经排好序的数组,运行时间是n的线性函数; 最坏情况,输入数组是逆序,运行时间是n的二次函数。 1.2 核心代码 public void sort(){int temp;for(int i = 1; i<arraytoSort.