定义模型

将表映射到结构体

对于每个表,您都需要定义一个相应的 Go 结构体(模型)。Bun 将导出的结构体字段映射到表列,并忽略未导出的字段。

type User struct {
	bun.BaseModel `bun:"table:users,alias:u"`

    ID    int64  `bun:"id,pk,autoincrement"`
    Name  string `bun:"name,notnull"`
    email string // unexported fields are ignored
}

结构体标签

Bun 使用合理的默认值来生成名称并推断类型,但您可以使用以下结构体标签来覆盖默认值。

标签注释
bun.BaseModel `bun:"table:table_name"`覆盖默认表名。
bun.BaseModel `bun:"alias:table_alias"`覆盖默认表别名。
bun.BaseModel `bun:"select:view_name"`覆盖 SELECT 查询的表名。
bun:"-"忽略该字段。
bun:"column_name"覆盖默认列名。
bun:"alt:alt_name"备用列名。在迁移期间很有用。
bun:",pk"将列标记为主键并应用 notnull 选项。支持多个/复合主键。
bun:",autoincrement"将列标记为 PostgreSQL 中的 serial,MySQL 中的 autoincrement,以及 MSSQL 中的 identity。还应用 nullzero 选项。
bun:"type:uuid"覆盖默认 SQL 类型。
bun:"default:gen_random_uuid()"告诉 CreateTable 设置 DEFAULT 表达式。
bun:",notnull"告诉 CreateTable 添加 NOT NULL 约束。
bun:",unique"告诉 CreateTable 添加唯一约束。
bun:",unique:group_name"一组列的唯一约束。
bun:",nullzero"将 Go 零值编组为 SQL NULLDEFAULT(如果支持)。
bun:",scanonly"仅使用此字段扫描查询结果,并在 SELECT/INSERT/UPDATE/DELETE 中忽略。
bun:",array"使用 PostgreSQL 数组。
bun:",json_use_number"使用 json.Decoder.UseNumber 解码 JSON。
bun:",msgpack"使用 MessagePack 编码/解码数据。
DeletedAt time.Time `bun:",soft_delete"`在模型上启用软删除。

表名

Bun 通过下划线将结构体名称生成表名和别名。它还将表名复数化,例如,结构体 ArticleCategory 获取表名 article_categories 和别名 article_category

要覆盖生成的名称和别名

type User struct {
	bun.BaseModel `bun:"table:myusers,alias:u"`
}

要为 SELECT 查询指定不同的表名

type User struct {
	bun.BaseModel `bun:"select:users_view,alias:u"`
}

ModelTableExpr

使用 ModelTableExpr 方法,您可以覆盖结构体表名,但不能覆盖别名。ModelTableExpr 应始终使用相同的表别名,例如

type User struct {
	bun.BaseModel `bun:"table:myusers,alias:u"`
}

// Good.
db.NewSelect().Model(&User{}).ModelTableExpr("all_users AS u")
db.NewSelect().Model(&User{}).ModelTableExpr("deleted_users AS u")

// Bad.
db.NewSelect().Model(&User{}).ModelTableExpr("all_users AS user")
db.NewSelect().Model(&User{}).ModelTableExpr("deleted_users AS deleted")

列名

Bun 通过下划线将结构体字段名称生成列名。例如,结构体字段 UserID 获取列名 user_id

要覆盖生成的列名

type User struct {
	Name string `bun:"myname"`
}

SQL 命名约定

使用 snake_case在新窗口中打开 标识符作为表名和列名。如果您遇到虚假的 SQL 解析器错误,请尝试用双引号(MySQL 为反引号)引起来标识符,以检查问题是否消失。

警告

不要使用 SQL 关键字在新窗口中打开(例如
orderuser)作为标识符。

警告

不要使用区分大小写的名称,因为此类名称将折叠为小写,例如,
UserOrders 变为 userorders

列类型

Bun 从结构体字段类型生成列类型。例如,Go 类型 string 被转换为 SQL 类型 varchar

要覆盖生成的列类型

type User struct {
    ID int64 `bun:"type:integer"`
}

NULL

要表示 SQL NULL,您可以使用指针或 sql.Null* 类型

type Item struct {
    Active *bool
    // or
    Active sql.NullBool
}

例如

  • (*bool)(nil)sql.NullBool{} 表示 NULL
  • (*bool)(false)sql.NullBool{Valid: true} 表示 FALSE
  • (*bool)(true)sql.NullBool{Valid: true, Value: true} 表示 TRUE

Go 零值和 NULL

要将 Go 零值编组为 NULL,请使用 nullzero 标签

type User struct {
	Name string `bun:",nullzero"`
}

DEFAULT

要指定默认 SQL 表达式,请使用 nullzeronotnulldefault 标签的组合

type User struct {
	Name string `bun:",nullzero,notnull,default:'unknown'"`
}

err := db.NewCreateTable().Model((*User)(nil)).Exec(ctx)
CREATE TABLE users (
  name text NOT NULL DEFAULT 'unknown'
);

自动时间戳

使用以下代码在 INSERT 上自动设置创建和更新时间

type User struct {
	CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
	UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
}

如果您不想设置更新时间,请使用 bun.NullTime

type User struct {
	CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
	UpdatedAt bun.NullTime
}

您还可以使用 钩子 设置结构体字段

var _ bun.BeforeAppendModelHook = (*User)(nil)

func (u *User) BeforeAppendModel(ctx context.Context, query bun.Query) error {
	switch query.(type) {
	case *bun.InsertQuery:
		u.CreatedAt = time.Now()
	case *bun.UpdateQuery:
		u.UpdatedAt = time.Now()
	}
	return nil
}

扩展模型

您可以使用 extend 标签选项向现有模型添加/删除字段。新模型将继承原始模型的表名和别名。

type UserWithCount struct {
	User `bun:",extend"`

	Name		string `bun:"-"` // remove this field
	AvatarCount int				 // add a new field
}

嵌入结构体

Bun 允许使用前缀将模型嵌入到另一个模型中,例如

type Role struct {
	Name     string
	Users    Permissions `bun:"embed:users_"`
	Profiles Permissions `bun:"embed:profiles_"`
	Roles    Permissions `bun:"embed:roles_"`
}

type Permissions struct {
	View   bool
	Create bool
	Update bool
	Delete bool
}

上面的代码生成以下表

CREATE TABLE roles (
    name TEXT,

    users_view BOOLEAN,
    users_create BOOLEAN,
    users_update BOOLEAN,
    users_delete BOOLEAN,

    profiles_view BOOLEAN,
    profiles_create BOOLEAN,
    profiles_update BOOLEAN,
    profiles_delete BOOLEAN,

    roles_view BOOLEAN,
    roles_create BOOLEAN,
    roles_update BOOLEAN,
    roles_delete BOOLEAN
);

另请参阅