【问题标题】:GORM create record that might already existGORM 创建可能已经存在的记录
【发布时间】:2020-01-05 01:33:00
【问题描述】:

我在我的 Go 应用程序中使用 gorm 和 postgres。

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

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

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

我知道我可以使用事务首先检查具有给定 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

即使一切都按预期进行。

【问题讨论】:

    标签: postgresql go go-gorm


    【解决方案1】:

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

    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
    }
    

    【讨论】:

      【解决方案2】:

      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

      【讨论】:

        【解决方案3】:

        在 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")
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多