gorm框架学习

目录

1.gorm介绍:

2.安装gorm

3.使用grom框架:

3.1新增

3.2查询

3.2.1 一般查询

 3.2.2 Where查询

 3.2.3 结构体或者map查询

3.2.4 高级查询

3.2.5 链式操作

 3.2.6 立即执行方法

3.2.7 Scopes(范围)

3.3 更新

3.3.1 单个更新

 3.3.2 批量更新

3.4删除

 3.4.1 删除单个

3.4.2 批量删除

3.4.3  软删除

3.4.4 物理删除


1.gorm介绍:

gorm 框架是国内的大神 jinzhu 基于 go 语言开源实现的一款数据库 orm 框架. 【gorm】一词恢弘大气,前缀 go 代表 go 语言, 后缀 orm 全称 Object Relation Mapping,指的是使用对象映射的方式,让使用方能够像操作本地对象实例一样轻松便捷地完成远端数据库的操作.orm框架的好处是提高开发效率

缺点是:

  • 牺牲执行性能【中间多了一个环节】
  • 牺牲灵活性
  • 弱化SQL能力

gorm 框架开源地址为: https://github.com/go-gorm/gorm

gorm官网文档:GORM - The fantastic ORM library for Golang, aims to be developer friendly.

如果想了解一下框架原理,可以看一下知乎上学霸写的文章。

gorm 框架原理&源码解析:https://zhuanlan.zhihu.com/p/663707360

2.安装gorm

导入依赖

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

注意:

  • GORM 的开发已经迁移至 github.com/go-gorm,import 路径也修改为 gorm.io/gorm ,对于以前的项目,您可以继续使用 github.com/jinzhu/gorm
  • 数据库驱动被拆分为独立的项目,例如:github.com/go-gorm/mys…,且它的 import 路径也变更为 gorm.io/driver/mysql

连接数据库:

我以mysql为例子:

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

func main() {
	dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}
}

gorm操作数据库:

package main

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

// UserInfo 用户信息
type UserInfo struct {
	ID     uint
	Name   string
	Gender string
	Hobby  string
}

func main() {
	dsn := "root:@tcp(127.0.0.1:3306)/gorm?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	// 自动迁移
	err = db.AutoMigrate(&UserInfo{})
	if err != nil {
		panic("failed to migrate")
	}

	u1 := UserInfo{1, "杨洋", "男", "篮球"}

	// 创建记录
	db.Create(&u1)
	db.Create(&UserInfo{2, "王楚然", "女", "足球"})
	// 查询
	var u = new(UserInfo)
	db.First(&u, 1) // 根据整型主键查找
	fmt.Printf("%#v\n", u)

	var uu UserInfo
	db.First(&uu, "hobby=?", "足球") //查找 hobby 字段值为 足球 的记录
	fmt.Printf("%#v\n", uu)

	// 更新
	db.Model(&u).Update("hobby", "排球")
	//Update - 更新多个字段
	db.Model(&u).Updates(UserInfo{Name: "肖战", Hobby: "跳舞"}) // 仅更新非零值字段
	db.Model(&uu).Updates(map[string]interface{}{"Hobby": "演戏", "Name": "赵丽颖"})

	// 删除
	db.Delete(&u, 1)
}

在使用ORM工具时,通常我们需要在代码中定义模型(Models)与数据库中的数据表进行映射,在GORM中模型(Models)通常是正常定义的结构体、基本的go类型或它们的指针。 同时也支持sql.Scannerdriver.Valuer接口(interfaces)。

为了方便模型定义,GORM内置了一个gorm.Model结构体。gorm.Model是一个包含了ID, CreatedAt, UpdatedAt, DeletedAt四个字段的Golang结构体。

// 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
}

也可以自定义嵌套

type Author struct {
    Name  string
    Email string
}

type Blog struct {
  ID      int
  Author  Author `gorm:"embedded"`   //使用embedden关键字
  Upvotes int32
}
// 等效于
type Blog struct {
  ID    int64
  Name  string
  Email string
  Upvotes  int32
}

还可以定义到每一个字段的长度,大小。索引等等

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"` // 设置会员号(member number)唯一并且不为空
  Num          int     `gorm:"AUTO_INCREMENT"` // 设置 num 为自增类型
  Address      string  `gorm:"index:addr"` // 给address字段创建名为addr的索引
  IgnoreMe     int     `gorm:"-"` // 忽略本字段
}

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

结构体标签定义的字段

GORM 默认会使用名为ID的字段作为表的主键。

// 根据 User 的字段创建 `deleted_users` 表 db.Table("deleted_users").AutoMigrate(&User{})

3.使用grom框架:

3.1新增

创建一条记录

package main

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

type User struct {
	ID       uint
	Name     string
	Age      uint8
	Birthday time.Time
}

func main() {
	dsn := "root:@tcp(127.0.0.1:3306)/gorm?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}
	// 自动迁移
	err = db.AutoMigrate(&User{})
	if err != nil {
		panic("failed to migrate")
	}
	user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}

	result := db.Create(&user)       // 通过数据的指针来创建
	fmt.Println(user.ID)             // 返回插入数据的主键
	fmt.Println(result.Error)        // 返回 error
	fmt.Println(result.RowsAffected) // 返回插入记录的条数
}

创建多条记录

users := []User{
		{Name: "Jinzhu", Age: 18, Birthday: time.Now()},
		{Name: "Jackson", Age: 19, Birthday: time.Now()},
	}

	result := db.Create(users) 
    db.CreateInBatches(users, 100)  //批量处理,一次处理一千条
	fmt.Println(result.Error)        
	fmt.Println(result.RowsAffected) 

创建记录并为指定的字段分配值:

db.Select("Name", "Age", "CreatedAt").Create(&user)
// INSERT INTO `users` (`name`,`age`,`created_at`) VALUES ("jinzhu", 18, "2020-07-04 11:05:21.775")

创建记录并忽略要省略的传递字段的值:

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

还可以根据map创建,开发中推荐使用结构体创建

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},
	})

默认值问题:

通过tag定义字段的默认值,在创建记录时候生成的 SQL 语句会排除没有值或值为 零值 的字段。 在将记录插入到数据库后,Gorm会从数据库加载那些字段的默认值。

var user = User{Name: "", Age: 99} db.Create(&user)

上面代码实际执行的SQL语句是INSERT INTO users("age") values('99');,排除了零值字段Name,而在数据库中这一条数据会使用设置的默认值作为Name字段的值。

**注意:**所有字段的零值, 比如0, "",false或者其它零值,都不会保存到数据库内,但会使用他们的默认值。 如果你想避免这种情况,可以考虑使用指针或实现 Scanner/Valuer接口,比如:

// 使用指针
type User struct {
	ID   int64
	Name *string `gorm:"default:galeone"`
	Age  int64   
}
user := User{Name: new(string), Age: 18}
db.Create(&user)  // 此时数据库中该条记录name字段的值就是''

3.2查询

3.2.1 一般查询

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

// 根据主键查询第一条记录
var user User
result := db.First(&user)
fmt.Println(result.RowsAffected) // 返回找到的记录数
fmt.Println(result.Error)        // returns error or nil
 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;


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

//主键为字符串
db.First(&user, "id = ?", "1b74413f-f3b8-409f-ac47-e8c062e3472a")
// SELECT * FROM users WHERE id = "1b74413f-f3b8-409f-ac47-e8c062e3472a"

如果你想避免ErrRecordNotFound错误,你可以使用Find,比如db.Limit(1).Find(&user)Find方法可以接受struct和slice的数据。

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

 3.2.2 Where查询

// Get first matched record
db.Where("name = ?", "jinzhu").First(&user)
 SELECT * FROM users WHERE name = 'jinzhu' limit 1;

// Get all matched records
db.Where("name = ?", "jinzhu").Find(&users)
 SELECT * FROM users WHERE name = 'jinzhu';

// <>
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 users WHERE name in ('jinzhu','jinzhu 2');

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

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

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

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

 3.2.3 结构体或者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;

// 主键的切片
db.Where([]int64{20, 21, 22}).Find(&users)
// SELECT * FROM users WHERE id IN (20, 21, 22);

 当通过结构体进行查询时,GORM将会只通过非零值字段查询,这意味着如果你的字段值为0''false或者其他零值时,将不会被用于构建查询条件,若要在查询条件中包含零值,可以使用映射,该映射将包含所有键值作为查询条件

db.Where(&User{Name: "jinzhu", Age: 0}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu";
db.Where(map[string]interface{}{"Name": "jinzhu", "Age": 0}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 0;

 在使用 struct 进行搜索时,可以通过传递相关的字段名或 dbname 到 Where ()来指定在查询条件中使用 struct 中的哪些特定值,例如:

db.Where(&User{Name: "jinzhu"}, "name", "Age").Find(&users)// SELECT * FROM users WHERE name = "jinzhu" AND age = 0;
db.Where(&User{Name: "jinzhu"}, "Age").Find(&users)// SELECT * FROM users WHERE age = 0;

Not和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;

// Plain 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;

需要注意的是

GORM 允许扫描结果至 map[string]interface{} 或 []map[string]interface{},此时别忘了指定 Model 或 Table

result := map[string]interface{}{}
db.Model(&User{}).First(&result, "id = ?", 1)

var results []map[string]interface{}
db.Table("users").Find(&results)

3.2.4 高级查询

1.子查询

db.Where("amount > (?)", db.Table("orders").Select("AVG(amount)")).Find(&orders)
// SELECT * FROM "orders" WHERE amount > (SELECT AVG(amount) FROM "orders");

subQuery := db.Select("AVG(age)").Where("name LIKE ?", "name%").Table("users")
db.Select("AVG(age) as avgage").Group("name").Having("AVG(age) > (?)", subQuery).Find(&results)
// SELECT AVG(age) as avgage FROM `users` GROUP BY `name` HAVING AVG(age) > (SELECT AVG(age) FROM `users` WHERE name LIKE "name%")

2.选择查询

db.Select("name, age").Find(&users)
// SELECT name, age FROM users;

db.Select([]string{"name", "age"}).Find(&users)
// SELECT name, age FROM users;

db.Table("users").Select("COALESCE(age,?)", 42).Rows()
// SELECT COALESCE(age,'42') FROM users;

type User struct {
  ID     uint
  Name   string
  Age    int
  Gender string
  // 假设后面还有几百个字段...
}

type APIUser struct {
  ID   uint
  Name string
}

// 查询时会自动选择 `id`, `name` 字段
db.Model(&User{}).Limit(10).Find(&APIUser{})
// SELECT `id`, `name` FROM `users` LIMIT 10

3.排序和分页查询

db.Order("age desc, name").Find(&users)
// SELECT * FROM users ORDER BY age desc, name;

// 多字段排序
db.Order("age desc").Order("name").Find(&users)
// SELECT * FROM users ORDER BY age desc, name;

// 覆盖排序
db.Order("age desc").Find(&users1).Order("age", true).Find(&users2)
// SELECT * FROM users ORDER BY age desc; (users1)
// SELECT * FROM users ORDER BY age; (users2)

//分页查询
db.Limit(3).Find(&users)
// SELECT * FROM users LIMIT 3;

// Cancel limit condition with -1
db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
// SELECT * FROM users LIMIT 10; (users1)
// SELECT * FROM users; (users2)

db.Offset(3).Find(&users)
// SELECT * FROM users OFFSET 3;

db.Limit(10).Offset(5).Find(&users)
// SELECT * FROM users OFFSET 5 LIMIT 10;

// Cancel offset condition with -1
db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
// SELECT * FROM users OFFSET 10; (users1)
// SELECT * FROM users; (users2)

4.Count查询

必须位于链式编程的最后一位

db.Where("name = ?", "jinzhu").Or("name = ?", "jinzhu 2").Find(&users).Count(&count)
// SELECT * from USERS WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (users)
// SELECT count(*) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (count)

db.Model(&User{}).Where("name = ?", "jinzhu").Count(&count)
// SELECT count(*) FROM users WHERE name = 'jinzhu'; (count)

db.Table("deleted_users").Count(&count)
// SELECT count(*) FROM deleted_users;

db.Table("deleted_users").Select("count(distinct(name))").Count(&count)
// SELECT count( distinct(name) ) FROM deleted_users; (count)

5.其他查询,限制,分组,去重。连接等

//分组,限制
db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&results)



//去重
db.Distinct("name", "age").Order("name, age desc").Find(&results)


//连接查询
db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)

// multiple joins with parameter
db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Joins("JOIN credit_cards ON credit_cards.user_id = users.id").Where("credit_cards.number = ?", "411111111111").Find(&user)

6.Pluck和Scan

//Pluck,查询 model 中的一个列作为切片,
var ages []int64
db.Find(&users).Pluck("age", &ages)

var names []string
db.Model(&User{}).Pluck("name", &names)

db.Table("deleted_users").Pluck("name", &names)

// 想查询多个字段? 这样做:
db.Select("name, age").Find(&users)


//Scan,扫描结果至一个 struct.
type Result struct {
  Name string
  Age  int
}

var result Result
db.Table("users").Select("name, age").Where("name = ?", "Antonio").Scan(&result)

var results []Result
db.Table("users").Select("name, age").Where("id > ?", 0).Scan(&results)

// 原生 SQL
db.Raw("SELECT name, age FROM users WHERE name = ?", "Antonio").Scan(&result)

3.2.5 链式操作

// 创建一个查询
tx := db.Where("name = ?", "jinzhu")

// 添加更多条件
if someCondition {
  tx = tx.Where("age = ?", 20)
} else {
  tx = tx.Where("age = ?", 30)
}

if yetAnotherCondition {
  tx = tx.Where("active = ?", 1)
}
tx.Find(&user)
//sql生成
SELECT * FROM users where name = 'jinzhu' AND age = 30 AND active = 1;

 3.2.6 立即执行方法

立即执行方法:

Immediate methods ,立即执行方法是指那些会立即生成SQL语句并发送到数据库的方法, 他们一般是CRUD方法,比如:

Create, First, Find, Take, Save, UpdateXXX, Delete, Scan, Row, Rows

在 GORM 中使用多个立即执行方法时,后一个立即执行方法会复用前一个立即执行方法的条件 (不包括内联条件) 。

db.Where("name LIKE ?", "jinzhu%").Find(&users, "id IN (?)", []int{1, 2, 3}).Count(&count)





SELECT * FROM users WHERE name LIKE 'jinzhu%' AND id IN (1, 2, 3)

SELECT count(*) FROM users WHERE name LIKE 'jinzhu%'

3.2.7 Scopes(范围)

Scope是建立在链式操作的基础之上的。

基于它,你可以抽取一些通用逻辑,写出更多可重用的函数库。

func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
  return db.Where("amount > ?", 1000)
}

func PaidWithCreditCard(db *gorm.DB) *gorm.DB {
  return db.Where("pay_mode_sign = ?", "C")
}

func PaidWithCod(db *gorm.DB) *gorm.DB {
  return db.Where("pay_mode_sign = ?", "C")
}

func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
  return func (db *gorm.DB) *gorm.DB {
    return db.Scopes(AmountGreaterThan1000).Where("status IN (?)", status)
  }
}

db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)
// 查找所有金额大于 1000 的信用卡订单

db.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)
// 查找所有金额大于 1000 的 COD 订单

db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders)
// 查找所有金额大于 1000 且已付款或者已发货的订单

3.3 更新

3.3.1 单个更新

	dsn := "root:root@tcp(127.0.0.1:3306)/company?charset=utf8mb4&parseTime=True&loc=Local"
	//var model.UserModel
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}
	
	//查询操作
	var user UserInfo
	db.First(&user)
	user.Name = "测试小"
	user.Gender = "男"
	//全部更新,查出来所有字段赋值
	db.Save(&user)

	//更新单个值
	db.Model(&user).Update("name", "张三")
	

 3.3.2 批量更新

//更新多个属性,只会更新非零字段,如果要更新默认值,可以使用map更新
	db.Model(&user).Updates(UserInfo{Name: "hello", Hobby: "羽毛球", Gender: "女"})
    
	db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
	//更新多个属性
	db.Model(&user).UpdateColumns(UserInfo{Name: "hello", Hobby: "篮球"})
	//批量更新,没有指定主键
	_ = db.Model(UserInfo{}).Updates(UserInfo{Name: "hello", Hobby: "女"}).RowsAffected

	//通过gorm.Expr 更新
	db.Model(&user).Update("name", gorm.Expr(" ?", "张三"))

3.4删除

警告 删除记录时,请确保主键字段有值,GORM 会通过主键去删除记录,如果主键为空,GORM 会删除该 model 的所有记录。

 3.4.1 删除单个

// 删除现有记录
db.Delete(&email)
 DELETE from emails where id=10;

db.Delete(&User{}, 10)
// DELETE FROM users WHERE id = 10;

db.Delete(&User{}, "10")
// DELETE FROM users WHERE id = 10;

db.Delete(&users, []int{1,2,3})
// DELETE FROM users WHERE id IN (1,2,3);

// 带额外条件的删除
db.Where("name = ?", "jinzhu").Delete(&email)
// DELETE from emails where id = 10 AND name = "jinzhu";

3.4.2 批量删除

db.Where("email LIKE ?", "%jinzhu%").Delete(Email{})
// DELETE from emails where email LIKE "%jinzhu%";

db.Delete(Email{}, "email LIKE ?", "%jinzhu%")
// DELETE from emails where email LIKE "%jinzhu%";



var users = []User{{ID: 1}, {ID: 2}, {ID: 3}}
db.Delete(&users)
// DELETE FROM users WHERE id IN (1,2,3);

db.Delete(&users, "name LIKE ?", "%jinzhu%")
// DELETE FROM users WHERE name LIKE "%jinzhu%" AND id IN (1,2,3); 

3.4.3  软删除

如果一个 model 有 DeletedAt 字段,他将自动获得软删除的功能! 当调用 Delete 方法时, 记录不会真正的从数据库中被删除, 只会将DeletedAt 字段的值会被设置为当前时间

db.Delete(&user)
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;

// 批量删除
db.Where("age = ?", 20).Delete(&User{})
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;

// 查询记录时会忽略被软删除的记录
db.Where("age = 20").Find(&user)
// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;

// Unscoped 方法可以查询被软删除的记录
db.Unscoped().Where("age = 20").Find(&users)
// SELECT * FROM users WHERE age = 20;

如果你并不想嵌套gorm.Model,你也可以像下方例子那样开启软删除特性:

type User struct {
  ID      int
  Deleted gorm.DeletedAt
  Name    string
}

3.4.4 物理删除

// Unscoped 方法可以物理删除记录
db.Unscoped().Delete(&order)
// DELETE FROM orders WHERE id=10;

  • 14
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
数字乡村和智慧农业的数字化转型是当前农业发展的新趋势,旨在通过应用数字技术,实现农业全流程的再造和全生命周期的管理服务。中国政府高度重视这一领域的发展,提出“数字中国”和“乡村振兴”战略,以提升国家治理能力,推动城乡融合发展。 数字乡村的建设面临乡村治理、基础设施、产业链条和公共服务等方面的问题,需要分阶段实施《数字乡村发展战略纲要》来解决。农业数字化转型的需求包括满足市民对优质农产品的需求、解决产销对接问题、形成优质优价机制、提高农业劳动力素质、打破信息孤岛、提高农业政策服务的精准度和有效性,以及解决农业融资难的问题。 数字乡村建设的关键在于构建“1+3+4+1”工程,即以新技术、新要素、新商业、新农民、新文化、新农村为核心,推进数据融合,强化农业大数据的汇集功能。数字农业大数据解决方案以农业数字底图和数据资源为基础,通过可视化监管,实现区域农业的全面数字化管理。 数字农业大数据架构基于大数据、区块链、GIS和物联网技术,构建农业大数据中心、农业物联网平台和农村综合服务指挥决策平台三大基础平台。农业大数据中心汇聚各类涉农信息资源和业务数据,支持大数据应用。信息采集系统覆盖市、县、乡、村多级,形成高效的农业大数据信息采集体系。 农业物联网平台包括环境监测系统、视频监控系统、预警预报系统和智能控制系统,通过收集和监测数据,实现对农业环境和生产过程的智能化管理。综合服务指挥决策平台利用数据分析和GIS技术,为农业决策提供支持。 数字乡村建设包括三大服务平台:治理服务平台、民生服务平台和产业服务平台。治理服务平台通过大数据和AI技术,实现乡村治理的数字化;民生服务平台利用互联网技术,提供各类民生服务;产业服务平台融合政企关系,支持农业产业发展。 数字乡村的应用场景广泛,包括农业生产过程、农产品流通、农业管理和农村社会服务。农业生产管理系统利用AIoT技术,实现农业生产的标准化和智能化。农产品智慧流通管理系统和溯源管理系统提高流通效率和产品追溯能力。智慧农业管理通过互联网+农业,提升农业管理的科学性和效率。农村社会服务则通过数字化手段,提高农村地区的公共服务水平。 总体而言,数字乡村和智慧农业的建设,不仅能够提升农业生产效率和管理水平,还能够促进农村地区的社会经济发展,实现城乡融合发展,是推动中国农业现代化的重要途径。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值