ORM:表关系
介绍
如果您使用的是 4 种支持的表关系之一,Bun 可以帮助您连接和查询其他表
例如,您可以定义 Author
属于 Book
关系
type Book struct {
ID int64
AuthorID int64
Author Author `bun:"rel:belongs-to,join:author_id=id"`
}
type Author struct {
ID int64
}
然后使用 Relation
方法连接表
err := db.NewSelect().
Model(book).
Relation("Author").
Where("id = 1").
Scan(ctx)
SELECT
"book"."id", "book"."title", "book"."text",
"author"."id" AS "author__id", "author"."name" AS "author__name"
FROM "books"
LEFT JOIN "users" AS "author" ON "author"."id" = "book"."author_id"
WHERE id = 1
您可以在 一对一
/属于
关系中从父级查询子级,反之亦然
type Profile struct {
ID int64 `bun:",pk"`
Lang string
UserID int64
User *User `rel:"belongs-to"`
}
type User struct {
ID int64 `bun:",pk"`
Name string
Profile *Profile `bun:"rel:has-one"`
}
err := db.NewSelect().
Model(&user).
Where("id = 1").
Relation("Profile").
Scan(ctx)
err := db.NewSelect().
Model(&profile).
Where("id = 1").
Relation("User").
Scan(ctx)
仅选择书籍 ID 和关联的作者 ID
err := db.NewSelect().
Model(book).
Column("book.id").
Relation("Author", func (q *bun.SelectQuery) *bun.SelectQuery {
return q.Column("id")
}).
Where("id = 1").
Scan(ctx)
SELECT "book"."id", "author"."id" AS "author__id"
FROM "books"
LEFT JOIN "users" AS "author" ON "author"."id" = "book"."author_id"
WHERE id = 1
选择一本书并加入作者,但不选择它
err := db.NewSelect().
Model(book).
Relation("Author", func (q *bun.SelectQuery) *bun.SelectQuery {
return q.Exclude("*")
}).
Where("id = 1").
Scan(ctx)
SELECT "book"."id"
FROM "books"
LEFT JOIN "users" AS "author" ON "author"."id" = "book"."author_id"
WHERE id = 1
模拟 INNER JOIN
而不是 LEFT JOIN
err := db.NewSelect().
Model(book).
Relation("Author").
Where("id = 1").
Where("author.id IS NOT NULL").
Scan(ctx)
一对一关系
要定义一对一关系,请在字段中添加 bun:"rel:has-one"
标签。在以下 示例 中,我们有 User
模型,它有一个 Profile
模型。
// Profile belongs to User.
type Profile struct {
ID int64 `bun:",pk"`
Lang string
UserID int64
}
type User struct {
ID int64 `bun:",pk"`
Name string
Profile *Profile `bun:"rel:has-one,join:id=user_id"`
}
您可以指定多个连接列,例如,join:id=user_id,join:vendor_id=vendor_id
。
属于关系
要定义属于关系,您需要在字段中添加 bun:"rel:belongs-to"
标签。在以下 示例 中,我们定义了 Profile
模型,它属于 User
模型。
type Profile struct {
ID int64 `bun:",pk"`
Lang string
}
// User has one profile.
type User struct {
ID int64 `bun:",pk"`
Name string
ProfileID int64
Profile *Profile `bun:"rel:belongs-to,join:profile_id=id"`
}
您可以指定多个连接列,例如,join:profile_id=id,join:vendor_id=vendor_id
。
一对多关系
要定义一对多关系,请在字段中添加 bun:"rel:has-many"
。在以下 示例 中,我们有 User
模型,它有许多 Profile
模型。
type Profile struct {
ID int64 `bun:",pk"`
Lang string
Active bool
UserID int64
}
// User has many profiles.
type User struct {
ID int64 `bun:",pk"`
Name string
Profiles []*Profile `bun:"rel:has-many,join:id=user_id"`
}
您可以指定多个连接列,例如,join:id=user_id,join:vendor_id=vendor_id
。
多态一对多关系
您还可以通过使用 type
虚拟列和 polymorphic
选项来定义多态一对多关系。
在以下 示例 中,我们将所有评论存储在一个表中,但使用 trackable_type
列来保存此评论所属的模型表。
type Article struct {
ID int64
Name string
Comments []Comment `bun:"rel:has-many,join:id=trackable_id,join:type=trackable_type,polymorphic"`
}
type Post struct {
ID int64
Name string
Comments []Comment `bun:"rel:has-many,join:id=trackable_id,join:type=trackable_type,polymorphic"`
}
type Comment struct {
TrackableID int64 // Article.ID or Post.ID
TrackableType string // "article" or "post"
Text string
}
多对多关系
要定义多对多关系,请在字段中添加 bun:"m2m:order_to_items"
。您还需要在中间模型上定义两个一对一关系,并手动注册模型 (db.RegisterModel
)。
在以下 示例 中,我们有 Order
模型,它可以有许多项目,每个 Item
可以添加到多个订单中。我们还使用 OrderToItem
模型作为中间表来连接订单和项目。
func init() {
// Register many to many model so bun can better recognize m2m relation.
// This should be done before you use the model for the first time.
db.RegisterModel((*OrderToItem)(nil))
}
type Order struct {
ID int64 `bun:",pk"`
// Order and Item in join:Order=Item are fields in OrderToItem model
Items []Item `bun:"m2m:order_to_items,join:Order=Item"`
}
type Item struct {
ID int64 `bun:",pk"`
}
type OrderToItem struct {
OrderID int64 `bun:",pk"`
Order *Order `bun:"rel:belongs-to,join:order_id=id"`
ItemID int64 `bun:",pk"`
Item *Item `bun:"rel:belongs-to,join:item_id=id"`
}