【golang_gorm】ErrRecordNotFound 什么情况下返回? one record 还是 slice ?源码给出回答

 

 

1. 测试代码


type Topic struct {
	gorm.Model
	Title   string
	Content string
}

func main() {
	db, err := gorm.Open("sqlite3", "test.db")
	if err != nil {
		panic("Unable to connect to the database")
	}
	// db.LogMode(true)
	defer db.Close()

	// Automatic migration mode, which will automatically generate the topics table in the database
	// and the corresponding column(id, title, content,created_at,
	// updated_at, deleted_at)
	db.AutoMigrate(&Topic{})

	// Create a record
	db.Create(&Topic{Title: "welcome", Content: "foo"})

	// find a topic
	// The err value here is not empty, and the error "record not found" will be reported
	var topic Topic
	err = db.Where("id=?", 0).Find(&topic).Error
	fmt.Println("error:", err)
	fmt.Println("id of the topic:", topic.ID)
	// First
	err = db.Where("id=?", 0).First(&topic).Error
	fmt.Println("error:", err)
	fmt.Println("id of the topic:", topic.ID)
	// Last
	err = db.Where("id=?", 0).Last(&topic).Error
	fmt.Println("error:", err)
	fmt.Println("id of the topic:", topic.ID)

	// Find a list of topics
	// The err value here is nil
	var topics []Topic
	err = db.Where("id=?", 0).Find(&topics).Error
	fmt.Println("error:", err)
	fmt.Println("length of topics", len(topics))
	// First
	err = db.Where("id=?", 0).First(&topics).Error
	fmt.Println("error:", err)
	fmt.Println("length of topics", len(topics))
	// Last
	err = db.Where("id=?", 0).Last(&topics).Error
	fmt.Println("error:", err)
	fmt.Println("length of topics", len(topics))
}

2.  代码流程和结果

  • 初始化数据库连接,这里连接到本地 SQLite 数据库。
  • 自动创建数据库表结构,AutoMigrate 方法可以根据输入的参数反映对象的结构,从而根据规则映射应该在数据库中创建的表结构; 例如,传入 &topic {}将自动生成数据库中的主题表,包括 id、 title、 content、 create _ at、 update _ at、 delete _ at 等数据列。
  • 创建一个 Topic 记录
  • 查找 id 为0的 Topic 记录
  • 查找 id 为0的主题列表
error: record not found
id of the topic: 0
error: record not found
id of the topic: 0
error: record not found
id of the topic: 0
error: <nil>
length of topics 0
error: <nil>
length of topics 0
error: <nil>
length of topics 0

3. source code

// Find find records that match given conditions
func (s *DB) Find(out interface{}, where ...interface{}) *DB {
	  return s.NewScope(out).inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
}

// First find first record that match given conditions, order by primary key
func (s *DB) First(out interface{}, where ...interface{}) *DB {
	  newScope := s.NewScope(out)
	  newScope.Search.Limit(1)
	  return newScope.Set("gorm:order_by_primary_key", "ASC").inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
}

// Last find last record that match given conditions, order by primary key
func (s *DB) Last(out interface{}, where ...interface{}) *DB {
	  newScope := s.NewScope(out)
	  newScope.Search.Limit(1)
	  return newScope.Set("gorm:order_by_primary_key", "DESC").inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
}

// queryCallback used to query data from database
func queryCallback(scope *Scope) {
	// ...
	var (
		isSlice, isPtr bool
		resultType     reflect.Type
		results        = scope.IndirectValue()
	)
	// ...
	// The variable passed in to receive the retrieval result is either Slice or Struct
	// Other types of variables will report an error
	if kind := results.Kind(); kind == reflect.Slice {
		isSlice = true
		resultType = results.Type().Elem()
		results.Set(reflect.MakeSlice(results.Type(), 0, 0))

		if resultType.Kind() == reflect.Ptr {
			isPtr = true
			resultType = resultType.Elem()
		}
	} else if kind != reflect.Struct {
		scope.Err(errors.New("unsupported destination, should be slice or struct"))
		return
	}
	// ...
	// When assigning, if 0 rows are retrieved, and the received retrieval result is not a Slice type
	// will throw ErrRecordNotFound error
	if err := rows.Err(); err != nil {
		scope.Err(err)
	} else if scope.db.RowsAffected == 0 && !isSlice {
		scope.Err(ErrRecordNotFound)
	}
}

从源代码可以看出,在 GORM 中,First 和 Last 比 Find 有更多的限制和默认排序顺序,这三种方法之间没有本质区别。

 GORM 中的 queryCallback 方法。从源代码中可以知道,当分析和分配检索到的数据时,如果检索到0行,并且接收到的检索结果不是 Slice 类型的变量(此时它必须是 Sstruct 类型的变量) ,它将抛出 ErrRecordNotfound 错误。

4. 小结

本文通过一个例子说明了记录未找到的错误,并通过分析源代码详细说明了 GORM 抛出的 ErrRecordNotFind 的具体场景。

  1. 传入以接收检索结果的变量只能是 Struct 类型或 Slice 类型。
  2. 当传入变量为 Struct 类型时,如果检索到的数据为0,则会抛出 ErrRecordNotfound 错误。
  3. 当传入变量的类型为 Slice 时,在任何情况下都不会引发 ErrRecordNotfound 错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

自驱

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

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

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

打赏作者

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

抵扣说明:

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

余额充值