在某个项目中,有个数据验证的业务,即在数据库中查询数据是否存在,若数据已存在则返回错误并给前端提示。代码如下
Func01
func (t *ServiceInfo) Find(c *gin.Context, tx *gorm.DB, search *ServiceInfo) (*ServiceInfo, error) {
out := &ServiceInfo{}
err := tx.WithContext(c).Where(search).Find(out).Error
if err != nil {
return nil, err
}
return out, nil
}
gorm在之前的版本中,因为gorm的查询是链式的语句,所以中间出现的错误会存入到Error的参数集中处理。而且当没有查询到数据的时候也会得到错误ErrRecordNotFound。所以此代码就把错误同一处理,当controller中没有收到任何错误时,可以说明数据库中查询到了此数据,即校验重复了。
但是经过测试后发现无论如何err都是nil,且RowsAffected也明明为0。在网上也没有直接搜到这个坑的blog,于是我去翻了gorm最新的文档,发现了此段话!
即说明Find()方法不会再得到ErrRecordNotFound的错误
于是我采用了Find()和First()进行了对比的实验
Func02
func (t *ServiceInfo) Find(c *gin.Context, tx *gorm.DB, search *ServiceInfo) (*ServiceInfo, error) {
out := &ServiceInfo{}
resultFind := tx.WithContext(c).Where(search).Find(out)
resultFirst := tx.WithContext(c).Where(search).First(out)
log.Print("Find() Err: ", resultFind.Error, "\tFind Rows Affected: ", resultFind.RowsAffected)
log.Print("First() Err: ", resultFirst.Error, "\tFind Rows Affected: ", resultFirst.RowsAffected)
err := resultFind.Error
if err != nil {
return nil, err
}
return out, nil
}
得到输出
2022/07/25 10:00:35 Find() Err: <nil> Find Rows Affected: 0
2022/07/25 10:00:35 First() Err: record not found Find Rows Affected: 0
很明显,当查询不到结果的时候First()方法会返回ErrRecordNotFound,而Find()方法并不会
因此,若在不想改变代码原有的逻辑基础上,可以通过手动添加Error的方法来完成数据校验的工作
Func03
func (t *ServiceInfo) Find(c *gin.Context, tx *gorm.DB, search *ServiceInfo) (*ServiceInfo, error) {
out := &ServiceInfo{}
resultFind := tx.WithContext(c).Where(search).Find(out)
if resultFind.RowsAffected < 1 {
err := resultFind.AddError(gorm.ErrRecordNotFound)
if err != nil {
return nil, err
}
}
err := resultFind.Error
if err != nil {
return nil, err
}
return out, nil
}
即通过 resultFind.RowsAffected < 1
来判断是否查询到数据,再通过resultFind.AddError(gorm.ErrRecordNotFound)
手动添加
ErrRecordNotFound错误,藉此来完成在旧版本中存在的功能。
PS:我个人并不是很理解为什么要取消Find()方法中的这个错误提示
此实现方式仅供参考,如有更漂亮的方法希望不吝赐教