gorm: 填充新创建数据的相关字段

huangapple go评论153阅读模式
英文:

gorm: populating related field of newly created data

问题

我有以下相关的表:

type Person struct {
    ID      uint64 `json:"id" gorm:"primary_key;auto_increment"`
    Name    string `json:"name"`
    Surname string `json:"surname"`
}

type Book struct {
    ID        uint64    `json:"id" gorm:"primary_key;auto_increment"`
    Title     string    `json:"title" binding:"required,min=2,max=100" gorm:"type:varchar(100)"`
    Author    Person    `json:"author" binding:"required" gorm:"foreignkey:AuthorID"` // * 这里
    AuthorID  uint64    `json:"-"`
    WrittenIn string    `json:"written_in" gorm:"type:varchar(5)"`
    CreatedAt time.Time `json:"created_at" gorm:"default:CURRENT_TIMESTAMP"`
    UpdatedAt time.Time `json:"updated_at" gorm:"default:CURRENT_TIMESTAMP"`
}

我可以使用gormCreate()方法成功创建数据,使用以下函数:

func CreateBook(ctx *gin.Context) {
    // 验证输入
    var inputData CreateBookInput

    if err := ctx.ShouldBindJSON(&inputData); err != nil {
        ctx.JSON(401, gin.H{"status": "fail", "error": err.Error()})
    }

    // 创建书籍
    book := models.Book{Title: inputData.Title, AuthorID: inputData.AuthorID, WrittenIn: inputData.WrittenIn}

    database.DB.Create(&book).Preload("Author")
    // database.DB.Preload("Author").Create(&book)
    // database.DB.Set("gorm:auto_preload", true).Create(&book)

    ctx.JSON(201, gin.H{"status": "success", "book": book})
}

我想返回新创建的书籍及其作者。期望的响应如下:

"book": {
    "id": 10,
    "title": "Chinor ostidagi duel",
    "author": {
        "id": 3,
        "name": "John",
        "surname": "Smith"
    },
    "written_in": "1983",
    "created_at": "2022-01-07T17:07:50.84473824+05:00",
    "updated_at": "2022-01-07T17:07:50.84473824+05:00"
}

但是我找不到一种方法来填充相关的author字段。所以我得到的是:

"book": {
    "id": 10,
    "title": "Chinor ostidagi duel",
    "author": {
        "id": 0,       // 空
        "name": "",    // 空
        "surname": ""  // 空
    },
    "written_in": "1983",
    "created_at": "2022-01-07T17:07:50.84473824+05:00",
    "updated_at": "2022-01-07T17:07:50.84473824+05:00"
}

我尝试了以下方法,但都没有成功:

database.DB.Create(&book).Preload("Author")
database.DB.Preload("Author").Create(&book)
database.DB.Set("gorm:auto_preload", true).Create(&book)
database.DB.Create(&book).Set("gorm:auto_preload", true)

如何填充新创建数据的相关字段?

英文:

I have the following related tables:

type Person struct {
	ID      uint64 `json:"id" gorm:"primary_key;auto_increment"`
	Name    string `json:"name"`
	Surname string `json:"surname"`
}

type Book struct {
	ID        uint64    `json:"id" gorm:"primary_key;auto_increment"`
	Title     string    `json:"title" binding:"required,min=2,max=100" gorm:"type:varchar(100)"`
	Author    Person    `json:"author" binding:"required" gorm:"foreignkey:AuthorID"` // * here
	AuthorID  uint64    `json:"-"`                                                    // * here
	WrittenIn string    `json:"written_in" gorm:"type:varchar(5)"`
	CreatedAt time.Time `json:"created_at" gorm:"default:CURRENT_TIMESTAMP"`
	UpdatedAt time.Time `json:"updated_at" gorm:"default:CURRENT_TIMESTAMP"`
}

I can successfully create data with Create() method of gorm using this function:

func CreateBook(ctx *gin.Context) {
	// validating input
	var inputData CreateBookInput

	if err := ctx.ShouldBindJSON(&inputData); err != nil {
		ctx.JSON(401, gin.H{"status": "fail", "error": err.Error()})
	}

	// create book
	book := models.Book{Title: inputData.Title, AuthorID: inputData.AuthorID, WrittenIn: inputData.WrittenIn}

	database.DB.Create(&book).Preload("Author")
    // database.DB.Preload("Author").Create(&book)
	// database.DB.Set("gorm:auto_preload", true).Create(&book)
	
	ctx.JSON(201, gin.H{"status": "success", "book": book})
}

I want to return the newly created book with its author. Expected response:

"book": {
    "id": 10,
    "title": "Chinor ostidagi duel",
    "author": {
        "id": 3,
        "name": "John",
        "surname": "Smith"
    },
    "written_in": "1983",
    "created_at": "2022-01-07T17:07:50.84473824+05:00",
    "updated_at": "2022-01-07T17:07:50.84473824+05:00"
}

But I couldn't find a way to populate related 'author'. So what I get is:

"book": {
    "id": 10,
    "title": "Chinor ostidagi duel",
    "author": {
        "id": 0,       // empty
        "name": "",    // empty
        "surname": ""  // empty
    },
    "written_in": "1983",
    "created_at": "2022-01-07T17:07:50.84473824+05:00",
    "updated_at": "2022-01-07T17:07:50.84473824+05:00"
}

Itried these methods with no success:

database.DB.Create(&book).Preload("Author")
database.DB.Preload("Author").Create(&book)
database.DB.Set("gorm:auto_preload", true).Create(&book)
database.DB.Create(&book).Set("gorm:auto_preload", true)

How can I populate related field of newly created data?

答案1

得分: 2

你可以尝试使用AfterCreate钩子来解决问题。

func (b *Book) AfterCreate(tx *gorm.DB) (err error) {
    return tx.Model(b).Preload("Author").Error
}

你可以在这里找到有关钩子的更多信息。

英文:

One possible solution that you could try is to use the AfterCreate hook.

func (b *Book) AfterCreate(tx *gorm.DB) (err error) {
    return tx.Model(b).Preload("Author").Error
}

You can find more info about hooks here.

答案2

得分: 0

Preload是链式方法,Create是完成方法。只有完成方法会生成并执行SQL。

所以...

  1. 在创建书籍后,通过id查找作者
if err := database.DB.Create(&book).Error; err != nil {
  return err
}

// 不会抛出未找到错误
database.DB.Limit(1).Find(&book.Author, book.AuthorID)

ctx.JSON(201, gin.H{"status": "success", "book": book})
  1. 每次加载作者数据时,使用钩子函数
// 创建和更新
// func (b *Book) AfterSave(tx *gorm.DB) (err error) {
// 仅创建
func (b *Book) AfterCreate(tx *gorm.DB) (err error) {
  // 如果需要,处理错误
  tx.Limit(1).Find(&b.Author, b.AuthorID)
  return
}
英文:

Preload is chain method, Create is finisher method. only finisher method will generate and execute SQL.

So...

1 Find author by id after create book

if err ;= database.DB.Create(&book).Error; err != nil {
  return err
}

// will not throw not found error
database.DB.Limit(1).Find(&book.Author, book.AuthorID)

ctx.JSON(201, gin.H{"status": "success", "book": book})

2 Load author data every times, use hook

// create and update
// func (b *Book) AfterSave(tx *gorm.DB) (err error) {
// just create
func (b *Book) AfterCreate(tx *gorm.DB) (err error) {
  // handle error if you want
  tx.Limit(1).Find(&b.Author, b.AuthorID)
  return
}

huangapple
  • 本文由 发表于 2022年1月7日 21:19:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/70621877.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定