如何使用Gorm从数据库中返回新创建的记录

发布于 2025-02-10 13:30:47 字数 3015 浏览 2 评论 0原文

我有一个创建新用户的函数,但是获取用户值的推定方法不包括数据库创建的自动化值(ID,create_at)

type User struct {
    Id         string `json:"id" gorm:"primaryKey"`
    Email      string `json:"email"`
    Password   string `json:"password"`
    Created_At string `json:"created_at"`
    Updated_At string `json:"updated_at"`
    Deleted_At string `json:"deleted_at"`
}

type UserRequest struct {
    Email    string `json:"email"`
    Password string `json:"password"`
}

func CreateUserRepo(newUser UserRequest) (*User, error) {

    user := User{Email: newUser.Email, Password: newUser.Password}
    fmt.Println(user)
    result := services.PostgresSQLDB.Select("Email", "Password").Create(&user)
    fmt.Println(result.RowsAffected)

    if result.Error != nil {
        modules.Logger.Error(result.Error)
        return nil, result.Error
    }

    return &user, nil

}

您可以看到我在ID和Create_at中获得一个空字符串,尽管这些值已由我的数据库自动生成。

{
    "id": "",
    "email": "[email protected]",
    "password": "password",
    "created_at": "",
    "updated_at": "",
    "deleted_at": ""
}

对某些扩展的测试

我认为这取决于编写Gorm期望的“适当”类型。

  1. 如果我将gorm.model添加到我的struct中,ID似乎会返回UUID,但是它还返回了一堆我不想要的重复的字段(ID,ID,create creats created,UpdateTat,deleteTedat,deletedat,deletedat )。删除gorm.model,id不再让我退还由Postgres
    type User struct {
        gorm.Model
        Id        uuid.UUID      `json:"id"`
        Email     string         `json:"email"`
        Password  string         `json:"password"`
        CreatedAt time.Time      `json:"created_at"`
        UpdatedAt time.Time      `json:"updated_at"`
        DeletedAt gorm.DeletedAt `json:"deleted_at"`
    }
{
    "ID": 0,
    "CreatedAt": "0001-01-01T00:00:00Z",
    "UpdatedAt": "0001-01-01T00:00:00Z",
    "DeletedAt": null,
    "id": "b4dea226-3be2-4ee7-8548-67ccbbbcbcca",
    "email": "[email protected]",
    "password": "password",
    "created_at": "2022-06-25T20:59:27.872198797+01:00",
    "updated_at": "2022-06-25T20:59:27.872198797+01:00",
    "deleted_at": null
}

数据库postgres

-- CreateTable
CREATE TABLE "users" (
    "id" UUID NOT NULL DEFAULT gen_random_uuid(),
    "email" TEXT NOT NULL,
    "password" TEXT,
    "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMP(3) NOT NULL,
    "deleted_at" TIMESTAMP(3),

    CONSTRAINT "users_pkey" PRIMARY KEY ("id")
);

I have a function that creates a new user, however the reccomended way to get the values of the user does not include the autogenerated values created by the database (id, created_at)

type User struct {
    Id         string `json:"id" gorm:"primaryKey"`
    Email      string `json:"email"`
    Password   string `json:"password"`
    Created_At string `json:"created_at"`
    Updated_At string `json:"updated_at"`
    Deleted_At string `json:"deleted_at"`
}

type UserRequest struct {
    Email    string `json:"email"`
    Password string `json:"password"`
}

func CreateUserRepo(newUser UserRequest) (*User, error) {

    user := User{Email: newUser.Email, Password: newUser.Password}
    fmt.Println(user)
    result := services.PostgresSQLDB.Select("Email", "Password").Create(&user)
    fmt.Println(result.RowsAffected)

    if result.Error != nil {
        modules.Logger.Error(result.Error)
        return nil, result.Error
    }

    return &user, nil

}

You can see i get an empty string for both id and created_at although those values have been auto generated by my database.

{
    "id": "",
    "email": "[email protected]",
    "password": "password",
    "created_at": "",
    "updated_at": "",
    "deleted_at": ""
}

enter image description here

testing

To some extend i think this comes down to writing the "proper" types that gorm expects.

  1. It seems like Id will return the uuid if i add gorm.Model to my struct, but it also returns back a bunch of fields that seem like duplicates that i dont want (ID, CreatedAt, UpdatedAt, DeletedAt). Removing gorm.Model, Id no longer gives me back the uuid generated by postgres
    type User struct {
        gorm.Model
        Id        uuid.UUID      `json:"id"`
        Email     string         `json:"email"`
        Password  string         `json:"password"`
        CreatedAt time.Time      `json:"created_at"`
        UpdatedAt time.Time      `json:"updated_at"`
        DeletedAt gorm.DeletedAt `json:"deleted_at"`
    }
{
    "ID": 0,
    "CreatedAt": "0001-01-01T00:00:00Z",
    "UpdatedAt": "0001-01-01T00:00:00Z",
    "DeletedAt": null,
    "id": "b4dea226-3be2-4ee7-8548-67ccbbbcbcca",
    "email": "[email protected]",
    "password": "password",
    "created_at": "2022-06-25T20:59:27.872198797+01:00",
    "updated_at": "2022-06-25T20:59:27.872198797+01:00",
    "deleted_at": null
}

enter image description here

database postgres

-- CreateTable
CREATE TABLE "users" (
    "id" UUID NOT NULL DEFAULT gen_random_uuid(),
    "email" TEXT NOT NULL,
    "password" TEXT,
    "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMP(3) NOT NULL,
    "deleted_at" TIMESTAMP(3),

    CONSTRAINT "users_pkey" PRIMARY KEY ("id")
);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

最偏执的依靠 2025-02-17 13:30:47

我终于在不包含的情况下找到了答案。

添加默认返回子句,返回所有新创建的值。
https://gorm.io/docs/update.html#returnurning -data-from-modified行

Clauses.(clause.Returning{})

model.go

type User struct {
    ID        uuid.UUID      `json:"id" gorm:"primaryKey:type:uuid"`
    Email     string         `json:"email"`
    Password  string         `json:"password"`
    CreatedAt time.Time      `json:"created_at"`
    UpdatedAt time.Time      `json:"updated_at"`
    DeletedAt gorm.DeletedAt `json:"deleted_at"`
}

repository.go

func CreateUserRepo(newUser UserRequest) (*User, error) {

    hash, errHash := modules.HashPassword(newUser.Password)

    if errHash != nil {
        return nil, errHash
    }

    user := User{Email: newUser.Email, Password: *hash}
    result := services.PostgresSQLDB.Clauses(clause.Returning{}).Select("Email", "Password").Create(&user)
    fmt.Println(result.RowsAffected)
    fmt.Println(&user)

    if result.Error != nil {
        modules.Logger.Error(result.Error)
        return nil, result.Error
    }

    return &user, nil

}

感谢@thefool评论此发现。

I finally found the answer without comprising.

Adding the default return clause, returns all the newly created values.
https://gorm.io/docs/update.html#Returning-Data-From-Modified-Rows

Clauses.(clause.Returning{})

model.go

type User struct {
    ID        uuid.UUID      `json:"id" gorm:"primaryKey:type:uuid"`
    Email     string         `json:"email"`
    Password  string         `json:"password"`
    CreatedAt time.Time      `json:"created_at"`
    UpdatedAt time.Time      `json:"updated_at"`
    DeletedAt gorm.DeletedAt `json:"deleted_at"`
}

repository.go

func CreateUserRepo(newUser UserRequest) (*User, error) {

    hash, errHash := modules.HashPassword(newUser.Password)

    if errHash != nil {
        return nil, errHash
    }

    user := User{Email: newUser.Email, Password: *hash}
    result := services.PostgresSQLDB.Clauses(clause.Returning{}).Select("Email", "Password").Create(&user)
    fmt.Println(result.RowsAffected)
    fmt.Println(&user)

    if result.Error != nil {
        modules.Logger.Error(result.Error)
        return nil, result.Error
    }

    return &user, nil

}

thanks to @TheFool comment for this find.

自找没趣 2025-02-17 13:30:47

据我所知,GORM不支持其他任何对主密钥的自动增量的东西。因此,要么您将其保留在PostgreSQL侧(就像您一样),要么在创建对象之前(使用beforecreate hook)在GO中生成自己的UUID。

另外,gorm.model定义如下:

type Model struct {
  ID        uint           `gorm:"primaryKey"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt gorm.DeletedAt `gorm:"index"`
}

您不必使用它,但是如果不使用,请添加gorm:“ primarykey”关键字段。默认情况下,主字段具有自动增量,就您的情况而言,我建议使用自动启动:false将其禁用。

type User struct {
    Id        uuid.UUID      `gorm:"primaryKey;autoIncrement:false" json:"id"`
    Email     string         `json:"email"`
    Password  string         `json:"password"`
}

当您让PostgreSQL处理默认值(而不是GORM)时,您必须再次查询对象,以访问您的ID UUID和create_at_at timestamp。

另请注意,您可以使用gormvaluerinterface在创建时使用SQL Expr。但是您仍然需要再次查询您的记录。 ( https://gorm.io/data_io/data_types.htata_types.htmll#gormvalumvaluervalueririnterface

in您有兴趣处理所有问题的情况,这里有一个带有和没有gorm.model的示例。

package main

import (
    "fmt"
    "time"

    "github.com/google/uuid"
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

var DB *gorm.DB

type User struct {
    UUID      uuid.UUID `gorm:"primaryKey;autoIncrement:false"`
    Name      string
    CreatedAt time.Time
}

type UserWithGormModel struct {
    gorm.Model
    UUID uuid.UUID `gorm:"primaryKey;autoIncrement:false"`
    Name string
}

func (u *User) BeforeCreate(tx *gorm.DB) (err error) {

    // This is an example, refer to https://pkg.go.dev/github.com/google/UUID for good usage
    u.UUID = uuid.New()

    u.CreatedAt = time.Now()

    return
}

func (u *UserWithGormModel) BeforeCreate(tx *gorm.DB) (err error) {

    // This is an example, refer to https://pkg.go.dev/github.com/google/UUID for good usage
    u.UUID = uuid.New()

    return
}

func ConnectDatabase() {

    database, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }

    if err != nil {
        panic("Failed to connect to database!")
    }

    database.AutoMigrate(&User{}, &UserWithGormModel{})

    DB = database
}

func main() {
    ConnectDatabase()

    user := User{Name: "Bob"}
    DB.Create(&user)
    fmt.Printf("User{UUID: %s, User.Name: %s, CreatedAt: %s}\n", user.UUID, user.Name, user.CreatedAt)

    user2 := UserWithGormModel{Name: "John"}
    DB.Create(&user2)
    fmt.Printf("UserWithGormModel{UUID: %s, Name: %s, CreatedAt: %s}\n", user2.UUID, user2.Name, user2.CreatedAt)
}

输出:

User{UUID: 8551636a-540f-4733-8179-3f0cc45daf4f, User.Name: Bob, CreatedAt: 2022-06-28 11:40:10.9225724 +0200 CEST}
UserWithGormModel{UUID: 2a6f94bd-a42b-4316-90be-0e93ea5091a6, Name: John, CreatedAt: 2022-06-28 11:40:10.9318004 +0200 CEST}

As far as I know, GORM doesn't support anything else that integer auto increment for the primary key. So either you keep that on PostgreSQL side (like you did) or you generate your own UUID in Go before creating the object (with BeforeCreate hook).

Also, the gorm.Model definition is the following:

type Model struct {
  ID        uint           `gorm:"primaryKey"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt gorm.DeletedAt `gorm:"index"`
}

You don't have to use it, but if you don't, add gorm:"primaryKey" to your primary key field. By default primary field have auto increment, for your case, I would recommend to disable it with autoIncrement:false.

type User struct {
    Id        uuid.UUID      `gorm:"primaryKey;autoIncrement:false" json:"id"`
    Email     string         `json:"email"`
    Password  string         `json:"password"`
}

As you let PostgreSQL handle default value (and not GORM), you have to query again the object in order to access your id UUID and created_at TIMESTAMP.

Also note that you can use GormValuerInterface to use an SQL Expr on creation. But you will still have to query again your record. (https://gorm.io/docs/data_types.html#GormValuerInterface)

In case you are interested to handle all on Go side, here an example with and without gorm.Model.

package main

import (
    "fmt"
    "time"

    "github.com/google/uuid"
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

var DB *gorm.DB

type User struct {
    UUID      uuid.UUID `gorm:"primaryKey;autoIncrement:false"`
    Name      string
    CreatedAt time.Time
}

type UserWithGormModel struct {
    gorm.Model
    UUID uuid.UUID `gorm:"primaryKey;autoIncrement:false"`
    Name string
}

func (u *User) BeforeCreate(tx *gorm.DB) (err error) {

    // This is an example, refer to https://pkg.go.dev/github.com/google/UUID for good usage
    u.UUID = uuid.New()

    u.CreatedAt = time.Now()

    return
}

func (u *UserWithGormModel) BeforeCreate(tx *gorm.DB) (err error) {

    // This is an example, refer to https://pkg.go.dev/github.com/google/UUID for good usage
    u.UUID = uuid.New()

    return
}

func ConnectDatabase() {

    database, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }

    if err != nil {
        panic("Failed to connect to database!")
    }

    database.AutoMigrate(&User{}, &UserWithGormModel{})

    DB = database
}

func main() {
    ConnectDatabase()

    user := User{Name: "Bob"}
    DB.Create(&user)
    fmt.Printf("User{UUID: %s, User.Name: %s, CreatedAt: %s}\n", user.UUID, user.Name, user.CreatedAt)

    user2 := UserWithGormModel{Name: "John"}
    DB.Create(&user2)
    fmt.Printf("UserWithGormModel{UUID: %s, Name: %s, CreatedAt: %s}\n", user2.UUID, user2.Name, user2.CreatedAt)
}

Output:

User{UUID: 8551636a-540f-4733-8179-3f0cc45daf4f, User.Name: Bob, CreatedAt: 2022-06-28 11:40:10.9225724 +0200 CEST}
UserWithGormModel{UUID: 2a6f94bd-a42b-4316-90be-0e93ea5091a6, Name: John, CreatedAt: 2022-06-28 11:40:10.9318004 +0200 CEST}
烟凡古楼 2025-02-17 13:30:47

我希望它能有所帮助

var data map[string]interface{}
err := DB.Model(models.User{}).Clauses(clause.Returning{}).Create(data).Error
if err != nil {
    return models.User{}, err
}

id := fmt.Sprint(data["id"])
var user models.User
DB.First(&user, id)
return user, nil

I hope it can help

var data map[string]interface{}
err := DB.Model(models.User{}).Clauses(clause.Returning{}).Create(data).Error
if err != nil {
    return models.User{}, err
}

id := fmt.Sprint(data["id"])
var user models.User
DB.First(&user, id)
return user, nil
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文