关系模型
在本节中我们将学习模型之间的关系处理。
样例
type User struct {
ID uuid.UUID
Email string
Password string
Books Books `has_many:"books" order_by:"title asc"`
FavoriteSong Song `has_one:"song" fk_id:"u_id"`
Houses Addresses `many_to_many:"users_addresses"`
}
type Book struct {
ID uuid.UUID
Title string
Isbn string
User User `belongs_to:"user"`
UserID uuid.UUID
}
type Song struct {
ID uuid.UUID
Title string
UserID uuid.UUID `db:"u_id"`
}
type Address struct {
ID uuid.UUID
Street string
HouseNumber int
}
type Books []Book
type Addresses []Address
可用的结构标签
has_many
: Will load all records from thebooks
table that have a column nameduser_id
, or the column specified withfk_id
that matches theUser.ID
value.belongs_to
: Will load a record fromusers
table that have a column namedid
that matches withBook.UserID
value.has_one
: Will load a record from thesongs
table that have a column nameduser_id
, or the column specified withfk_id
that matches theUser.ID
value.many_to_many
: Will load all records from theaddresses
table through the tableusers_addresses
. Tableusers_addresses
MUST defineaddress_id
anduser_id
columns to matchUser.ID
andAddress.ID
values. You can also define afk_id
tag that will be used in the target association i.e.addresses
table.fk_id
: Defines the column name in the target association that matches model ID. In the example aboveSong
has a column namedu_id
that represents id ofusers
table. When loadingFavoriteSong
,u_id
will be used instead ofuser_id
.order_by
: Used inhas_many
andmany_to_many
to indicate the order for the association when loading. The format to use isorder_by:"<column_name> <asc | desc>"
预加载关联
u := Users{}
err := tx.Eager().Where("name = 'Mark'").All(&u) // preload all associations for user with name 'Mark', i.e Books, Houses and FavoriteSong
默认情况下Eager会预加载说有的关联数据。有时间我们可能只需要其中一两种,可以调用的指定:
err = tx.Eager("Books").Where("name = 'Mark'").All(&u) // preload only Books association for user with name 'Mark'.
已经存在的对象加载关联数据
tx.Load(&u) // load all associations for user, i.e Books, Houses and FavoriteSong
tx.Load(&u, "Books") // load only the Books associations for user
创建的时候关联
book := Book{Title: "Pop Book", Description: "Pop Book", Isbn: "PB1"}
tx.Create(&book)
song := Song{Title: "Don't know the title"}
tx.Create(&song)
addr := Address{HouseNumber: 1, Street: "Golang"}
tx.Create(&addr)
user := User{
Name: "Mark Bates",
Books: Books{Book{ID: book.ID}},
FavoriteSong: song,
Houses: Addresses{
addr,
},
}
err := tx.Create(&user)
- Books 是 一对多的关系。
- FavoriteSong 是一对一的关系。
- Houses 是多对多的关系。
而书是属于一个人的。保存的时候将指定user.ID。
book := Book{
Title: "Pop Book",
Description: "Pop Book",
Isbn: "PB1",
User: user,
}
tx.Create(&book)
热创建
上面的列子中各模型都实例化了,也可以采用匿名的方式。
user := User{
Name: "Mark Bates",
Books: Books{{Title: "Pop Book", Description: "Pop Book", Isbn: "PB1"}},
FavoriteSong: Song{Title: "Don't know the title"},
Houses: Addresses{
Address{HouseNumber: 1, Street: "Golang"},
},
}
err := tx.Eager().Create(&user)
属于关系:
book := Book{
Title: "Pop Book",
Description: "Pop Book",
Isbn: "PB1",
User: User{
Name: nulls.NewString("Larry"),
},
}
tx.Eager().Create(&book)
一对一模型
type Head struct {
ID int
BodyID int `db:"body_id"`
Body *Body `belongs_to:"body"`
}
type Body struct {
ID int
Head Head `has_one:"head"`
}
// Eager creation:
// Create a body with its head.
b := &models.Body{
Head: models.Head{},
}
if err := tx.Eager().Create(b); err != nil {
return err
}
// Eager fetch all bodies with their head.
bodies = &models.Bodies{}
if err := c.Eager().All(bodies); err != nil {
log.Printf("err: %v", err)
return
}
log.Printf("eager fetch: %v", bodies)