gorm框架学习---crud接口之创建(代码片段)

大忽悠爱忽悠 大忽悠爱忽悠     2022-12-07     707

关键词:

Gorm框架学习---CRUD接口之创建


本文内容摘抄自Gorm 2022-8月份官方文档教程,如果Gorm框架后续有更新,还是以最新版本的官方文档为准


系列文章:

Gorm框架学习–入门


环境准备

先确保能够连接上指定的数据库并且将相关表创建好,这里用mysql作为演示:

package main

import (
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

const MYSQL_ADDR ="user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"

type User struct 
    gorm.Model
	Name     string
	Age      int
	Birthday time.Time


func main() 
	DB = openDB()
	createTable()


func createTable() 
	DB.AutoMigrate(&User)


func openDB() *gorm.DB 
	db, err := gorm.Open(mysql.Open(MYSQL_ADDR), &gorm.Config)
	if err != nil 
		panic("failed to connect database")
	
	return db


创建

创建记录

func main() 
	DB = openDB()
	user := UserName: "大忽悠", Age: 18, Birthday: time.Now()

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

	fmt.Println("返回插入数据的主键: ", user.ID)
	fmt.Println("返回 error: ", result.Error)
	fmt.Println("返回插入记录的条数: ", result.RowsAffected)


用指定的字段创建记录

创建记录并更新给出的字段。

	DB.Select("Name", "Age", "CreatedAt").Create(&user)
	// INSERT INTO `users` (`name`,`age`,`created_at`) VALUES ("大忽悠", 18, "2022-08-04 11:05:21.775")

创建一个记录且一同忽略传递给略去的字段值。

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")

批量插入

要有效地插入大量记录,请将一个 slice 传递给 Create 方法。 GORM 将生成单独一条SQL语句来插入所有数据,并回填主键的值,钩子方法也会被调用。

	var users = []UserName: "dhy1", Name: "dhy2", Name: "dhy3"
	DB.Create(&users)

	for _, user := range users 
		fmt.Printf("id=%d,name=%s,age=%d\\n", user.ID, user.Name, user.Age)
	

ERROR是因为Mysql5.7版本及以上版本的datetime值不能为’0000-00-00 00:00:00’,
解决方法: 修改mysql.int
在[mysqld]添加一项:sql_mode=NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,支持特殊的语法,这样就可以导入了,导入完毕后,移除兼容项即可。此方法简单,建议使用此方法。

使用 CreateInBatches 分批创建时,你可以指定每批的数量,例如:

	var users = []UserName: "dhy1", Name: "dhy2", Name: "dhy3"
	// 数量为 100
	DB.CreateInBatches(users, 100)

UpsertCreate With Associations 也支持批量插入

注意 使用CreateBatchSize 选项初始化 GORM 时,所有的创建& 关联 INSERT 都将遵循该选项

func openDB() *gorm.DB 
	//针对全局设置
	db, err := gorm.Open(mysql.Open(MYSQL_ADDR), &gorm.Config
		CreateBatchSize: 1,
	)
	if err != nil 
		panic("failed to connect database")
	
	return db

	var users = []UserName: "dhy1", Name: "dhy2", Name: "dhy3"
	//针对某次会话设置
	DB.Session(&gorm.SessionCreateBatchSize: 1).Create(users)

创建钩子

GORM 允许用户定义的钩子有 BeforeSave, BeforeCreate, AfterSave, AfterCreate 创建记录时将调用这些钩子方法,请参考 Hooks 中关于生命周期的详细信息

钩子方法常与模板方法模式搭配使用,通常暴露给用户自定义相关组件,以此提高框架整体可扩展性

func (u *User) BeforeCreate(tx *gorm.DB) (err error) 
  u.UUID = uuid.New()

    if u.Role == "admin" 
        return errors.New("invalid role")
    
    return

如果您想跳过 钩子 方法,您可以使用 SkipHooks 会话模式,例如:

//都是针对单词会话进行设置的
DB.Session(&gorm.SessionSkipHooks: true).Create(&user)

DB.Session(&gorm.SessionSkipHooks: true).Create(&users)

DB.Session(&gorm.SessionSkipHooks: true).CreateInBatches(users, 100)

根据 Map 创建

GORM 支持根据 map[string]interface[]map[string]interface 创建记录,例如:

	DB.Model(&User).Create(map[string]interface
		"Name": "DHY", "Age": 18,
	)

	// batch insert from `[]map[string]interface`
	DB.Model(&User).Create([]map[string]interface
		"Name": "dhy1", "Age": 18,
		"Name": "dhy2", "Age": 20,
	)

注意: 根据 map 创建记录时,association 不会被调用,且主键也不会自动填充


使用 SQL 表达式、Context Valuer 创建记录

GORM 允许使用 SQL 表达式插入数据,有两种方法实现这个目标。根据 map[string]interface自定义数据类型 创建,例如:

	// 通过 map 创建记录
	DB.Model(User).Create(map[string]interface
		"Name": clause.ExprSQL: "UPPER(?)", Vars: []interface"dhy",
		"age":  18,
	)

对应创建的sql语句为:

INSERT INTO `users` (`name`,`age`) VALUES (UPPER('dhy'),18)

通过自定义类型创建记录:

// 通过自定义类型创建记录
type Location struct 
    X, Y int


// Scan 方法实现了 sql.Scanner 接口
func (loc *Location) Scan(v interface) error 
  // Scan a value into struct from database driver


func (loc Location) GormDataType() string 
  return "geometry"


func (loc Location) GormValue(ctx context.Context, db *gorm.DB) clause.Expr 
  return clause.Expr
    SQL:  "ST_PointFromText(?)",
    Vars: []interfacefmt.Sprintf("POINT(%d %d)", loc.X, loc.Y),
  


type User struct 
  Name     string
  Location Location


db.Create(&User
  Name:     "jinzhu",
  Location: LocationX: 100, Y: 100,
)
// INSERT INTO `users` (`name`,`location`) VALUES ("jinzhu",ST_PointFromText("POINT(100 100)"))

高级选项

关联创建

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

upsert: 存在时更新,不存在时插入

	type CreditCard struct 
		gorm.Model
		Number   string
		UserID   uint
	

	type User struct 
		gorm.Model
		Name       string
		CreditCard CreditCard
	

	DB.Create(&User
		Name: "jinzhu",
		CreditCard: CreditCardNumber: "411111111111",
	)
	// INSERT INTO `users` ...
	// INSERT INTO `credit_cards` ...

您也可以通过 Select、 Omit 跳过关联保存,例如:

db.Omit("CreditCard").Create(&user)

// 跳过所有关联
db.Omit(clause.Associations).Create(&user)

默认值

您可以通过标签 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    `gorm:"default:18"`
	Age      int       `gorm:"default:100"`
	Birthday time.Time `gorm:"default:2022-08-23 21:28:27.329"`


func main() 
	DB = openDB()
	//我想保存相关数据类型的零值到数据库,但是由于默认值的存在,插入数据库的还是默认值
	DB.Create(&User
		Name: "",
		Age:  0,
	)

指针解决法:

type User struct 
	gorm.Model
	Name     *string   `gorm:"default:18"`
	Age      *int      `gorm:"default:100"`
	Birthday time.Time `gorm:"default:2022-08-23 21:28:27.329"`


func main() 
	DB = openDB()
	str := ""
	age := 0
	DB.Create(&User
		Name: &str,
		Age:  &age,
	)

Scanner/Valuer接口解决法:

type myString string

type User struct 
	gorm.Model
	Name     myString
	Age      int       `gorm:"default:100"`
	Birthday time.Time `gorm:"default:2022-08-23 21:28:27.329"`


//Scan 在从数据库读取记录到结构体时,当需要往某个字段注入值时,会先检查该字段是否实现了对应的Scan接口
//如果实现了,就利用该接口完成赋值
func (s *myString) Scan(src any) error 
	if src == nil 
		*s = ""
		return nil
	
	//... 我们需要在下面完成对当前字段的赋值
	return nil


func (s myString) Value() (driver.Value, error) 
	if s == "" 
		//如果为空,就记录一下
		fmt.Println("当前字段为空")
	
	//注意: 如果返回的类型也实现了Value接口,会继续调用
	//如果这里直接将s返回,会造成死循环,因为会不断去调用s的Value接口
	return "hhhhh", nil


func main() 
	DB = openDB()
	//在获取每个字段值时,会检查对应的字段有没有实现Value接口
	//如果实现了,就获取Value接口的返回值,作为最终结果
	DB.Create(&User
		Name: "xpy",
		Age:  0,
	)

Gorm操作对象属性前,会先去寻找Scan和Value方法,如果有则调用,这一点类似Java中操作对象属性通常使用Getter和Setter方法一般。


default:(-)标签可以让我们在字段为零值时,忽略该字段的插入。

type User struct 
	gorm.Model
	Name     myString
	Age      int       `gorm:"default:(-)"`
	Birthday time.Time `gorm:"default:2022-08-23 21:28:27.329"`


func main() 
	DB = openDB()
	DB.Create(&User
		Name: "xpy",
		Age:  0,
	)

  • Age为0时,生成的insert语句忽略了该字段的插入

  • Age不为0时,insert语句才会添加对应字段的插入


kratos学习从零使用kratos创建一个crud的demo,是gorm做数据库操作,经过几天研究,调试代码开源放到github上,还是非常方便的。服务也实现了crud的http接口。(代码片段)

目录前言1,关于kratos2,使用4,使用grpcul进行服务查看调用5,创建数据CRUD使用gorm6,做CRUD接口7,总结前言本文的原文连接是:https://blog.csdn.net/freewebsys/article/details/124262158未经博主允许不得转载。博主... 查看详情

kratos学习从零使用kratos创建一个crud的demo,是gorm做数据库操作,经过几天研究,调试代码开源放到github上,还是非常方便的。服务也实现了crud的http接口。(代码片段)

...og.csdn.net/freewebsys1,关于kratosKratos一套轻量级Go微服务框架,包含大量微服务相关框架及工具。https://go-kratos.dev/docs/网络上面的demo并不全面,从头来一点点进行研究学习。学到老活到老。2,使用golang需要使用1.18的... 查看详情

gorm基础--crud接口(代码片段)

1、Create1.1创建纪录user:=UserName:"Jinzhu",Age:18,Birthday:time.Now()result:=db.Create(&user)//passpointerofdatatoCreateuser.ID//回填插入数据的主键result.Error//返回的error信息result.RowsAffected//返回插入记录的个数1.2用选定的字段创建记录创... 查看详情

gin框架学习-gin框架和gorm框架搭建一个简单的api微服务(代码片段)

...术,不太熟悉的可以去看看我以前的文章快速安装gin框架:https://blog.csdn.net/weixin_46618592/article/details/125540869HTTP请求:https://blog.csdn.net/weixin_46618592/article/details/125565789Gorm入门指南:https://blog.csdn.net/weixin_46618592/articl... 查看详情

学习笔记golang之gorm学习笔记(代码片段)

一、模型定义1.模型定义模型是标准的struct,由Go的基本数据类型、实现了Scanner和Valuer接口的自定义类型及其指针或别名组成,如:typeUserstructIDuintNamestringEmail*stringAgeuint8Birthday*time.TimeMemberNumbersql.NullStringActivedAtsql 查看详情

gorm框架学习--入门(代码片段)

Gorm框架学习--入门引言快速入门模型定义约定gorm.Model高级选项字段级权限控制创建/更新时间追踪(纳秒、毫秒、秒、Time)嵌入结构体字段标签关联标签连接到数据库MySQL自定义驱动现有的数据库连接其他连接池参考引言... 查看详情

012-goorm框架之gorm测试(代码片段)

1:参考:https://github.com/jinzhu/gorm2:数据库脚本(pg)--createtableposts(idserialprimarykey,contenttext,authorvarchar(100),create_timetimestamptz);createtablecomments(idserialprimarykey,contenttext,authorvarc 查看详情

golang修仙记之gorm(代码片段)

学习了如何连接数据库、简单的错误处理、关闭数据库、创建表、创建表中的一条记录、读取表的记录、更新表的记录、删除标的记录packagemainimport("github.com/jinzhu/gorm"_"github.com/jinzhu/gorm/dialects/mysql""time")typeUserstructgorm.ModelNamestring... 查看详情

javaee框架技术之14ssm综合案例产品管理crud(代码片段)

SSM综合案例一、课程目标1.【掌握】SSM整合2.【√】学习Lombok使用3.【理解】Layui页面书写(备注:其他前端技术也可以)4.【理解】理解SSM综合案例表的结构5.【掌握】产品管理二、SSM整合Spring+SpringMVC+Mybatis–>SSMSpring+Struts2+Hiber... 查看详情

golang之orm框架gorm快速开始(代码片段)

Gorm快速入门Gorm是Go语言的ORM框架,其特点有:全特性ORM(几乎包含所有特性)模型关联(一对一,一对多,一对多(反向),多对多,多态关联)钩子(Before/AfterCreate/Save/Update/Delete/Find)预加载事务复合主... 查看详情

《mongodb入门教程》第06篇crud之创建文档(代码片段)

...文开始将会介绍MongoDB中的基本CRUD操作,首先我们来学习一下如何创建文档。使用insertOne()方法创建单个文档集合的insertOne()方法可以用于创建单个文档。该方法的语法如下:db.collection.insertOne(<document>,writeConcern:<docu... 查看详情

go语言学习之旅--gorm(代码片段)

Go语言学习之旅--gormgorm概述ORM简介安装gorm声明模型模型定义约定gorm.Modelgorm连接到数据库快速入门gorm的增删查改增gorm创建记录用指定的字段创建记录批量插入查检索单个对象用主键检索检索全部对象String条件Struct&Map条件更... 查看详情

mybatisplus学习笔记(代码片段)

文章目录MyBatisPlus学习笔记简介特性框架结构快速使用引入mybatis-plus相关maven依赖引入mybatis-plus在springboot中的场景启动器项目中其他需要导入依赖创建表SQL语句项目结构一览项目配置配置MapperScan注解application.properties配置创建Entit... 查看详情

golang之orm框架gorm快速开始(代码片段)

Gorm快速入门Gorm是Go语言的ORM框架,其特点有:全特性ORM(几乎包含所有特性)模型关联(一对一,一对多,一对多(反向),多对多,多态关联)钩子(Before/AfterCreate/Save/Update/Delete/Find)预加载事务复合主... 查看详情

go语言学习之旅--gorm(代码片段)

Go语言学习之旅--gormgorm概述ORM简介安装gorm声明模型模型定义约定gorm.Modelgorm连接到数据库快速入门gorm的增删查改增gorm创建记录用指定的字段创建记录批量插入查检索单个对象用主键检索检索全部对象String条件Struct&Map条件更... 查看详情

go语言学习之旅--gorm(代码片段)

Go语言学习之旅--gormgorm概述ORM简介安装gorm声明模型模型定义约定gorm.Modelgorm连接到数据库快速入门gorm的增删查改增gorm创建记录用指定的字段创建记录批量插入查检索单个对象用主键检索检索全部对象String条件Struct&Map条件更... 查看详情

深入学习flask框架之简单创建一个项目(代码片段)

  在前面一篇讲了如何创建一个虚拟环境,今天这一篇就来说说如何创建一个简单的Flask项目。关于Flask的具体介绍就不详细叙述了,我们只要知道它非常简洁、灵活和扩展性强就够了。它不像Django那样集成度特别高。Flask只是... 查看详情

javaee框架技术之7-mybatisorm框架入门基础crud(代码片段)

MyBatisORM概述在使用JDBC的时候,我们通常将数据直接返回,但现在也会将数据封装到实体类对象中,由对象携带数据。这样操作的时候,可以通过操作对象的方式操作数据。但是手写这类代码通常是繁琐的、重复... 查看详情