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.UUID4
gorm:"primary_key;type:uuid;default:uuid_generate_v4()"
ApplicationId string
gorm:"type:varchar(40); not null"
Phone string
json:"phone"
Email string
json:"email"
Beneficiaries []Beneficiary
gorm:"foreignkey:client_id" json:"beneficiaries"
Address string
gorm:"null" json:"address"
}
type Beneficiary struct {
ID strfmt.UUID4
gorm:"primary_key;type:uuid;default:uuid_generate_v4()"
FullName string
ClientId strfmt.UUID4
gorm:"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
我几乎可以肯定以某种方式倒退了。显然在互联网上围绕此功能存在很多混淆。
我只是想创建一个外键关系到 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.UUID4
gorm:"primary_key;type:uuid;default:uuid_generate_v4()"
ApplicationId string
gorm:"type:varchar(40); not null"
Phone string
json:"phone"
Email string
json:"email"
Beneficiaries []Beneficiary
gorm:"foreignkey:client_id" json:"beneficiaries"
Address string
gorm:"null" json:"address"
}
type Beneficiary struct {
ID strfmt.UUID4
gorm:"primary_key;type:uuid;default:uuid_generate_v4()"
FullName string
ClientId strfmt.UUID4
gorm:"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