MySQL - GORM 外键 Returns 空对象

MySQL - GORM ForeignKey Returns Empty Object

我几乎可以肯定以某种方式倒退了。显然在互联网上围绕此功能存在很多混淆。

我只是想创建一个外键关系到 Book 模型有一个 Author 的地方。使用 MySQL 8.

当我查询一本书时,我希望作者对象与它一起返回,所以可能我的查询也是错误的......我在这里。

models.go

package main

import (
    "github.com/jinzhu/gorm"
    uuid "github.com/satori/go.uuid"
    "time"
)

/*        Base Models
============================= */

type Base struct {
    ID        uuid.UUID  `gorm:"primary_key" json:"id"`
    CreatedAt *time.Time `json:"created_at"`
    UpdatedAt *time.Time `gorm:"index" json:"updated_at"`
    DeletedAt *time.Time `gorm:"index" json:"deleted_at"`
}

type BaseBook struct {
    ISBN        int64     `gorm:"primary_key;auto_increment:false;" json:"isbn"`
    Description string    `gorm:"type:longtext" json:"description"`
    Author      Author    `gorm:"foreignkey:AuthorId" json:"author"`
    AuthorId    uuid.UUID `json:"author_id"`
    Title       string    `json:"title"`
}

// BeforeCreate -  Sets a UUID instead of incremental numeric ID.
func (base *Base) BeforeCreate(scope *gorm.Scope) error {
    id := uuid.NewV4()
    return scope.SetColumn("ID", id)
}

/*          Tables
============================= */

type Book struct {
    Base
    BaseBook
    Events []Event `gorm:"foreignkey:ISBN"`
}

type Event struct {
    BaseBook
}

type Author struct {
    Base
    FirstName string `json:"first_name"`
    LastName  string `json:"last_name"`
    Middle    string `json:"middle"`
}

我在此处的种子函数中创建记录的方式有问题吗?

handlers.go

// GetSeedDatabase - Start seeding database with test data.
func GetSeedDatabase(w http.ResponseWriter, r *http.Request) {
    authors := getSeedDataAuthors()
    books := getSeedDataBooks()
    for _, author := range authors {
        for _, book := range books {
            if book.Author == author.ID.String() {
                newAuthor := Author{
                    Base: Base{
                        ID: author.ID,
                    },
                    FirstName: author.FirstName,
                    LastName:  author.LastName,
                    Middle:    author.Middle,
                }
                newBook := Book{
                    Base: Base{
                        ID: uuid.NewV4(),
                    },
                    BaseBook: BaseBook{
                        AuthorId:    newAuthor.ID,
                        ISBN:        book.ISBN,
                        Title:       book.Title,
                        Description: book.Description,
                    },
                }

                MySQL.Create(newAuthor)
                MySQL.Create(newBook)
            }
        }
    }

    var allAuthors []Author
    MySQL.Find(&allAuthors)

    var allBooks []Book
    MySQL.Find(&allBooks)

    if len(allAuthors) > 0 && len(allBooks) > 0 {
        w.Write([]byte("successfully seeded database"))
        return
    }

    w.Write([]byte("something went wrong seeding database"))
}

// GetAllBooks - Get all books in database.
func GetAllBooks(w http.ResponseWriter, r *http.Request) {
    var allBooks []Book
    MySQL.Find(&allBooks).Related(Author{})
    json.NewEncoder(w).Encode(allBooks)
}

当我点击 GetAllBooks 图书端点时,响应如下所示:

[
  {
    "id": "0c266efa-3c3c-4bb8-abe6-dbb9b8000cd8",
    "created_at": null,
    "updated_at": null,
    "deleted_at": null,
    "isbn": 9781593275846,
    "description": "JavaScript lies at the heart of almost every modern web application, from social apps to the newest browser-based games. Though simple for beginners to pick up and play with, JavaScript is a flexible, complex language that you can use to build full-scale applications.",
    "author": {
      "id": "00000000-0000-0000-0000-000000000000",
      "created_at": null,
      "updated_at": null,
      "deleted_at": null,
      "first_name": "",
      "last_name": "",
      "middle": ""
    },
    "author_id": "ba0d07bf-1a12-4742-989b-cdaa4c05ad72",
    "title": "Eloquent JavaScript, Second Edition",
    "Events": null
  },
  {
    "id": "0ea3e0fc-f917-46ea-b55b-d97e916bacd9",
    "created_at": null,
    "updated_at": null,
    "deleted_at": null,
    "isbn": 9781491904244,
    "description": "No matter how much experience you have with JavaScript, odds are you don’t fully understand the language. As part of the \"You Don’t Know JS\" series, this compact guide focuses on new features available in ECMAScript 6 (ES6), the latest version of the standard upon which JavaScript is built.",
    "author": {
      "id": "00000000-0000-0000-0000-000000000000",
      "created_at": null,
      "updated_at": null,
      "deleted_at": null,
      "first_name": "",
      "last_name": "",
      "middle": ""
    },
    "author_id": "c7f6e1b8-9e42-4666-bba8-dd9b229a362e",
    "title": "You Don't Know JS",
    "Events": null
  }
]

如您所见,返回的 Author 对象是它们自身的空版本。

我仍在尝试我在其他地方找到的外键示例的不同组合,但仍然没有成功。

更新

所以第一个问题是,如果您尝试通过模型上的注释添加外键(就像我所做的那样),GORM 不会直接添加外键。也许那是 MySQL8 的事情?我不确定,但我已经像这样手动添加了关系:

// addConstraints - Since GORM annotations are still broken for foreign keys we do it manually here.
func addConstraints(db *gorm.DB) *gorm.DB {
    log.Println("adding db table constraints")
    db.Model(Book{}).AddForeignKey(
        "author_id",
        "authors(id)",
        "SET DEFAULT",
        "SET DEFAULT",
    )

    return db
}

现在我可以预加载作者数据以随书一起返回:

// GetAllBooks - Get all books in database.
func GetAllBooks(w http.ResponseWriter, r *http.Request) {
    var allBooks []Book
    MySQL.Preload("Author").Find(&allBooks)
    json.NewEncoder(w).Encode(allBooks)
}

尝试使用 preload http://gorm.io/docs/preload.html

我会从我的代码中举一个例子

type Client struct { ID strfmt.UUID4gorm:"primary_key;type:uuid;default:uuid_generate_v4()" ApplicationId stringgorm:"type:varchar(40); not null" Phone stringjson:"phone" Email string json:"email" Beneficiaries []Beneficiarygorm:"foreignkey:client_id" json:"beneficiaries" Address stringgorm:"null" json:"address" } type Beneficiary struct { ID strfmt.UUID4gorm:"primary_key;type:uuid;default:uuid_generate_v4()" FullName string ClientId strfmt.UUID4gorm:"type:uuid REFERENCES app_rsv_client(id)" } func (dbm DbManager) GetClientByAppId(appId string) (*model.Client, error) { var client model.Client err := dbm.DB.Preload("Beneficiaries").Where("application_id = ?", appId).Find(&client).Error return &client, err }

参考这个回答:

你需要使用gorm的Preload功能。

例如:

gormDB.Preload("Author").Find(&allBooks)

官方文档:Gorm's Preloading