GORM创建可能已经存在的记录

时间:2019-09-01 21:46:48

标签: postgresql go go-gorm

我在Go应用中将gorm与postgres一起使用。

我想在数据库中创建一个新用户,但是该用户很有可能已经存在。如果是这样,我不想对数据库做任何事情,但是我想知道这一点,以便告诉用户。

好消息是,gorm.Create(..)已经做到了。尝试使用重复的唯一键创建记录将返回错误。有两个问题:

  1. 我想要更好的错误消息。我想编写面向用户的自定义错误消息,该错误消息的“此电子邮件地址已存在”与“发生实际的内部错误”不同。除了尝试解析Create()返回的错误字符串(似乎容易出错)以外,我不知道如何区分这两个事件。
  2. 我不想弄乱我的日志。使用已存在的对象调用Create()会将错误消息记录到stdout。我真的不认为这是一个“错误”,因为我期望它会发生,并且我不想在这些日志中充斥着这些警告。

我知道我可以使用事务来首先检查具有给定id的用户,然后在不存在该ID的情况下创建它们,但是似乎应该为这种基本问题提供一个更简单的解决方案。你应该怎么做?


我目前正在这样做:

func (self databaseWrapper) CreateUser(user *User) error {
    db := self.db
    db.NewRecord(*user)
    err := db.Create(user).Error
    if err != nil {
        if db.Where(user.ID).Take(&User{}).Error == nil {
            return fmt.Errorf("A user already exists with id %v", user.ID)
        }

        if db.Where(User{Email: user.Email}).Take(&User{}).Error == nil {
            return fmt.Errorf("A user already exists with the given email address: %v", user.Email)
        }

        return fmt.Errorf("Error creating user")
    }
    return nil
}

效率低下,输出难看:

go test

(/home/quinn/workspace/aev/sensor/backend/server/database.go:125)
[2019-09-01 14:45:40]  pq: duplicate key value violates unique constraint "users_pkey"

(/home/quinn/workspace/aev/sensor/backend/server/database.go:125)
[2019-09-01 14:45:40]  pq: duplicate key value violates unique constraint "uix_users_email"
PASS
ok          3.215s

即使一切都按预期进行。

3 个答案:

答案 0 :(得分:1)

在 Gorm v1.21 中,我相信你可以......

配置记录器

import (
  gormLogger "gorm.io/gorm/logger"
)

func main() {
  db, err := gorm.Open(
    sqlite.Open("test.db"),
    &gorm.Config{
      Logger: gormLogger.New(
        log.New(os.Stdout, "\r\n", log.LstdFlags),
        gormLogger.Config {
          LogLevel: gormLogger.Silent,
          // IgnoreRecordNotFoundError: true,
        },
      ),
    },
  )
}

捕获并打印您自己的错误消息

result := db.Where("email = ?", "test@test.com").Take(&user)

if !errors.Is(result.Error, gorm.ErrRecordNotFound) {
  fmt.Println("record already exists")
  // Or use a logger
  // logger.Info("record already exists")
}

答案 1 :(得分:0)

lib/pq是标准的postgres驱动程序。如果出现查询错误,它将返回一个pq.Error对象(即使您使用的是GORM)。 pq.Error类型具有一个Code字段,您可以检查该字段以查看错误原因。

if err, ok := err.(*pq.Error); ok && err.Code.Name() == "unique_violation" {
    // handle error
}

Error code reference

lib/pq Go doc

答案 2 :(得分:0)

要添加到上一个答案,当前您还可以使用类似的方法来检查错误代码(在示例中:检查重复的键)。

import "github.com/jackc/pgx"
...
func isDuplicateKeyError(err error) bool {
    pgErr, ok := err.(pgx.PgError)
    if ok {
        // unique_violation = 23505
        return pgErr.Code == "23505"

    }
    return false
}