GORM快速入门

crud 指的creat retrieve update delete增加,查询,更新,删除四种操作

ORM,对象关系映射,是一种框架格式,显示了映射关系

迁移

创建表,查看表,重命名表,删除表

type User struct {
	ID   int
	Name string
}

func main() {
	db, err := gorm.Open(mysql.New(mysql.Config{
		DSN: "root:123456@tcp(127.0.0.1:3306)/db1?charset=utf8mb4&parseTime=True&loc=Local",
	}), &gorm.Config{
		SkipDefaultTransaction: false, //是否跳过事务事件,事务事件使得数据更安全
		NamingStrategy: schema.NamingStrategy{
			TablePrefix:   "t_",  //表 添加前缀
			SingularTable: false, //表名设置为单数
		},
		DisableForeignKeyConstraintWhenMigrating: true, //数据库采用逻辑外键,访问速度更快
	})
	if err != nil {
		fmt.Println(err)
	}
	//_ = db.AutoMigrate(&User{})         //自动迁移
	M := db.Migrator() //手动迁移
	//M.CreateTable(&User{})             //创建表
	//fmt.Println(M.HasTable(&User{}))     //查看表是否存在,("t_user")用表名的形式也可以 但是最好用结构体的形式,方便清楚
	//fmt.Println(M.DropTable(&User{})) //删除表
	if M.HasTable(&User{}) {
		M.RenameTable(&User{}, "a_users") //如果存在表就改名
	} else {
		M.CreateTable(&User{})                     //不存在就创建表
	}
}

CRUD
创建
func CreatedTest() { //首字母大写,对其他目录可见
    //创建单条数据
	//GlobalDb.Create(&TestUser{Name: "景之", Age: 20}) //记得设置数据库编码格式为utf8
	//GlobalDb.Omit("Name").Create(&TestUser{Name: "景之", Age: 20})  跳过名字创建Age
	//GlobalDb.Select("Name").Create(&TestUser{Name: "景之", Age: 20}) 只创建Name
    
    //创建多条数据
	GlobalDb.Create(&[]TestUser{
		{Name: "景之", Age: 20},
		{Name: "郭龙", Age: 21},
		{Name: "弛子", Age: 20},
		{Name: "小艺", Age: 20},
	})
}
查询

以下查的好多都是单条数据,如果是要查询多条数据也很简单,只需要

var Users TestUser
//查询语句
GlobalDb.Find(&Users)
fmt.Println(Users)
//如此就可,就是换成了切片

查询单个对象

db.First(&user)

db.Take(&user)

db.Last(&user)

result := db.First(&user)
result.RowsAffected // 返回找到的记录数  比如说咱要找叫做小艺的同学,那么学校可能有好几个人叫小艺,几个就是记录数

查询map型切片和结构体

func TestFind() {
    //查询结构体,map型切片
	//var result = make(map[string]interface{})
	//GlobalDb.Model(&TestUser{}).First(&result)
    //fmt.Println(result)
	
	var User TestUser
    //根据主键排序查询
    //GlobalDb.Model(&TestUser{}).Take(&User)
    //GlobalDb.Model(&TestUser{}).First(&User)
	GlobalDb.Model(&TestUser{}).Last(&User)
	fmt.Println(User)
}

主键检索

//直接检索到第几条数据
db.First(&user, 10)
// SELECT * FROM users WHERE id = 10;

db.First(&user, "10")
// SELECT * FROM users WHERE id = 10;

//多条检索查询
db.Find(&users, []int{1,2,3})
// SELECT * FROM users WHERE id IN (1,2,3);

查询总共有几条数据

var Users []TestUser //加上[] 就是切片,包含所有数据否则TestUser只是代表找到这个表(表就是结构体)
//查询所有对象
res := GlobalDb.Find(&Users) //返回error 和 RowsAffected
fmt.Println(res.RowsAffected) //输出有几条数据

//打印所有数据
var Users []TestUser 
//找到所有对象
GlobalDb.Find(&Users) 
fmt.Println(Users)    

条件查询

//根据string字段查询
var User TestUser
//GlobalDb.Where("name = ?", "景之").First(&User)

GlobalDb.Where("name = ? AND age = 20", "景之").First(&User)

//GlobalDb.Where("name = ? AND age >= ?", "景之", "19").Find(&Users) //???

fmt.Println(User)
//官网还有好多,这只是最基本的用法
//<>排除这个的数据
//LIKE模糊,在条件位置加%%,例如%j%

内联

//string形式
GlobalDb.First(&User, "id = ?", 5)
//结构体形式
GlobalDb.First(&User, TestUser{Name: "jz"})
//map形式
GlobalDb.First(&User, map[string]interface{}{"Name": "jz"})

往下基本看文档自己都会

高级查询

智能字段,自定义api,

type UserInfo struct {
	//自定义智能字段
	Name string
	Age  uint8
}

func TestFind() {
	var u UserInfo
	GlobalDb.Model(&TestUser{}).Where("Name LIKE ?", "%小%").Find(&u)
	fmt.Println(u)
}
//结果是:{小艺 20}
更新

形式上和查询基本一样,最后的改为下边的三个关键词,对应即可

func TestUpdate() {
	//update 只更新选择的字段
	//updates 跟新所有字段,形式1 map 形式2 结构体,结构体零值不参与更新
	//save    everything更新
	GlobalDb.Model(&TestUser{}).Where("Name = ?", "jz").Update("name", "jz大帅哥")
}
删除
func TestDelete() {
	var user []TestUser
	//Unscoped真的删除这一行,没有Unscoped是软删除
	//gorm.Model含有gorm.deletedat,拥有软删除的能力
	//拥有软删除能力的模型调用 Delete 时,记录不会被数据库。但 GORM 会将 DeletedAt 置为当前时间, 并且你不能再通过普通的查询方法找到该记录。
	GlobalDb.Unscoped().Where("namE", "jz大帅哥").Delete(&user) //name这种条件都是大小写不太区分的
}

原生
GlobalDb.Row(原生语句)
关联
belongsTo

belongs to 会与另一个模型建立了一对一的连接

这种模型的每一个实例都“属于”另一个模型的一个实例

//GirlGod可以有很多个User
type User struct {
  gorm.Model
  Name      string
  GirlGodID int
  GirlGod GirlGod
}

type GirlGod struct {
  ID   int
  Name string
}

预加载

var girl GirlGod
GlobalDb.Preload("Dog").First(&girl, 2)
fmt.Println(girl)
//女神出门带着添狗,preload预加载,把天狗带上
Has One
// User 有一张 CreditCard,UserID 是外键
type User struct {
  gorm.Model
  GirlGod GirlGod // 追随者有了女神
}

type GirlGod struct {
  gorm.Model
  Number string
  UserID uint //女神带有追随着
}
Has Many

和has one 区别就是,把Dog变成了Dogs切片

type Dog struct {
	gorm.Model
	Name      string
	GirlGodID uint //狗链子

}

type GirlGod struct {
	gorm.Model
	Name string
	Dogs []Dog //拿到狗链子
}

func One2one() {
	d1 := Dog{
		Model: gorm.Model{
			ID: 1,
		},
		Name: "汪汪1号",
	}
	d2 := Dog{
		Model: gorm.Model{
			ID: 2,
		},
		Name: "汪汪2号",
	}
	g := GirlGod{
		Model: gorm.Model{
			ID: 1,
		},
		Name: "女神",
		Dogs: []Dog{d1, d2}, //汪汪1号和汪汪2号都在追女神 ID都是1
	}
	GlobalDb.Create(&g)

查询

//预加载全部
var girl GirlGod
GlobalDb.Preload("Dogs").First(&girl)
fmt.Println(girl)
//选择性预加载。内联式查询
GlobalDb.Preload("Dogs", "name = ?", "汪汪1号").First(&girl)
//当条件很多时候,可以用个函数
GlobalDb.Preload("Dogs", func(db *gorm.DB) *gorm.DB{
    return db.Where("name = ?", "汪汪1号")
}).First(&girl)
多态
  • 支持一对一和一对多
type Jiazi struct {
	ID          uint
	Name        string
	Xiaofengche Xiaofengche `gorm:"polymorphic:Owner;"`
}
type Yujie struct {
	ID          uint
	Name        string
	Xiaofengche Xiaofengche `gorm:"polymorphic:Owner;"`
}
type Xiaofengche struct {
	ID        uint
	Name      string
	OwnerType string
	OwnerID   uint
}

func Polymorphic() {
	GlobalDb.Create(&Jiazi{Name: "夹子", Xiaofengche: Xiaofengche{
		Name: "小风车",
	}})
	GlobalDb.Create(&Yujie{Name: "御姐", Xiaofengche: Xiaofengche{
		Name: "大风车",
	}})
}
关联外键

关联id

type Jiazi struct {
	ID          uint
	Name        string
	Xiaofengche []Xiaofengche `gorm:"foreignKey:JiaziName"` //还是关联的id,只不过起的名字叫jiazi_name
}
type Xiaofengche struct {
	ID        uint
	Name      string
	JiaziName string
}

func Polymorphic() {
	GlobalDb.AutoMigrate(&Jiazi{}, &Xiaofengche{})
	GlobalDb.Create(&Jiazi{Name: "大夹子", Xiaofengche: []Xiaofengche{
		{Name: "小风车1"},
		{Name: "小风车2"},
	}})
}

关联Name

  • 把关联语句换为下边这个
  • references引用指向自己,大夹子
`gorm:"foreignKey:JiaziName;references:Name"`
事务
单层普通事务
type TMG struct {
	ID   uint
	Name string
}

func TestTransaction() {
	flag := false
	GlobalDb.AutoMigrate(&TMG{})
	GlobalDb.Transaction(func(tx *gorm.DB) error {
		tx.Create(&TMG{Name: "汉子"})
		tx.Create(&TMG{Name: "高大威猛"})
		fmt.Println("上边执行过了")
		if flag {
			return nil
		} else {
			return errors.New("躲开汉子")
		}
	})
}
嵌套事务
func TestTransaction() {
	GlobalDb.AutoMigrate(&TMG{})
	GlobalDb.Transaction(func(tx *gorm.DB) error {
		tx.Create(&TMG{Name: "高大威猛"})
		tx.Transaction(func(tx *gorm.DB) error {
			tx.Create(&TMG{Name: "汉子"})
			return errors.New("躲开了汉子")
		})
		fmt.Println("执行高大威猛出现,汉子不出现")
		return nil
	})
}

手动事务
//手动事务
	tx := GlobalDb.Begin()
	tx.Create(&TMG{Name: "汉子"})
	tx.Create(&TMG{Name: "高大威武"})
	tx.Commit()
SavePoint、RollbackTo
tx := GlobalDb.Begin()
tx.Create(&TMG{Name: "汉子"})
tx.SavePoint("duo")
tx.Create(&TMG{Name: "高大威武"})
tx.RollbackTo("duo")
tx.Commit()

总结:写的有点乱了,我尽量给他整清楚了,因为我也是看b站up主+看文档学习有点乱,但是我真的尽量整清楚了。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
gorm scopes是Golang中使用的一种功能,用定义和应用查询作用域。它可以帮助我们在查询数据库时,根据不同的条件和需求,动态地构建查询语句。 使用gorm scopes,我们可以将一组查询条件封装成一个作用域(scope),然后在需要的时候应用到查询中。这样可以使代码更加模块化和可复用,同时也能提高查询的灵活性和可读性。 在gorm中,我们可以通过定义结构体的方法来创建作用域。这些方法需要接收一个gorm.DB类型的参数,并返回一个gorm.DB类型的结果。在方法内部,我们可以使用gorm提供的各种查询方法来构建查询条件,例如Where、Order、Limit等。 下面是一个使用gorm scopes的示例: ```go type User struct { ID uint Name string Age int } func (db *gorm.DB) AgeGreaterThan(age int) *gorm.DB { return db.Where("age > ?", age) } func main() { db, err := gorm.Open("mysql", "user:password@tcp(localhost:3306)/database") if err != nil { panic(err) } defer db.Close() var users []User db.Scopes(db.AgeGreaterThan(18)).Find(&users) } ``` 在上面的示例中,我们定义了一个名为AgeGreaterThan的作用域,它接收一个年龄参数,并返回一个添加了查询条件的gorm.DB对象。然后,在main函数中,我们通过调用Scopes方法并传入AgeGreaterThan作用域,来应用该作用域到查询中。 这样,最终执行的查询语句将会是`SELECT * FROM users WHERE age > 18`,并将结果存储到users变量中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不之道

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值