Model Definition

Model Definition

Model names are used for database data conversion and Database Schema Generation

Naming conventions

Table name conversion consists in translating camel case used for model names to snake case for table names as follows:

AuthUser -> auth_user
Auth_User -> auth__user
DB_AuthUser -> d_b__auth_user

In other words, all is converted to lower case and _ is the separator. Every uppercase add a separator before it, except the first one.

Custom table name

Using TableNameI interface:

type User struct {
	Id int
	Name string
}

func (u *User) TableName() string {
	return "auth_user"
}

If you set prefix to prefix_, the table name will be prefix_auth_user.

Custom index

Using TableIndexI interface:

Add index to one or more fields:

type User struct {
	Id    int
	Name  string
	Email string
}

// multiple fields index
func (u *User) TableIndex() [][]string {
	return [][]string{
		[]string{"Id", "Name"},
	}
}

// multiple fields unique key
func (u *User) TableUnique() [][]string {
	return [][]string{
		[]string{"Name", "Email"},
	}
}

Custom engine

Only supports MySQL database

The default engine is the default engine of the current database engine of your mysql settings.

Using TableEngineI interface:

type User struct {
	Id    int
	Name  string
	Email string
}

// Set engine to INNODB
func (u *User) TableEngine() string {
	return "INNODB"
}

Set parameters

orm:"null;rel(fk)"

Use ; as the separator of multiple settings. Use , as the separator if a setting has multiple values.

Ignore field

Use - to ignore field in the struct.

type User struct {
...
	AnyField string `orm:"-"`
...
}

auto

When Field type is int, int32, int64, uint, uint32 or uint64, you can set it as auto increment.

  • If there is no primary key in the model definition, the field Id with one of the types above will be considered as auto increment key

pk

Set as primary key. Used for using other type field as primary key.

null

Fields are NOT NULL by default. Set null to ALLOW NULL.

Name string `orm:"null"`

index

Add index for one field

unique

Add unique key for one field

Name string `orm:"unique"`

column

Set column name in db table for field.

Name string `orm:"column(user_name)"`

size

Default value for string field is varchar(255).

It will use varchar(size) after setting.

Title string `orm:"size(60)"`

digits / decimals

Set precision for float32 or float64.

Money float64 `orm:"digits(12);decimals(4)"`

Total 12 digits, 4 digits after point. For example: 12345678.1234

auto_now / auto_now_add

Created time.Time `orm:"auto_now_add;type(datetime)"`
Updated time.Time `orm:"auto_now;type(datetime)"`
  • auto_now: every save will update time.
  • auto_now_add: set time at the first save

This setting won’t affect massive update.

type

If set type as date, the field’s db type is date.

Created time.Time `orm:"auto_now_add;type(date)"`

If set type as datetime, the field’s db type is datetime.

Created time.Time `orm:"auto_now_add;type(datetime)"`

Time Precision

type User struct {
...
Created time.Time `orm:"type(datetime);precision(4)"`
...
}

default value

you could use it like:


import (
"github.com/beego/beego/v2/client/orm/filter/bean"
"github.com/beego/beego/v2/client/orm"
)

type DefaultValueTestEntity struct {
Id            int
Age           int `default:"12"`
AgeInOldStyle int `orm:"default(13);bee()"`
AgeIgnore     int
}

func XXX() {
    builder := bean.NewDefaultValueFilterChainBuilder(nil, true, true)
    orm.AddGlobalFilterChain(builder.FilterChain)
    o := orm.NewOrm()
    _, _ = o.Insert(&User{
        ID: 1,
        Name: "Tom",
    })
}

NewDefaultValueFilterChainBuilderwill create an instance of DefaultValueFilterChainBuilder In beego v1.x, the default value config looks like orm:default(xxxx) But the default value in 2.x is default:xxx, so if you want to be compatible with v1.x, please pass true as compatibleWithOldStyle

Comment

Set comment value for field.

type User struct {
	...
	Status int `orm:"default(1);description(this is status)"`
	...
}

Relationships

One to one

RelOneToOne:

type User struct {
	...
	Profile *Profile `orm:"null;rel(one);on_delete(set_null)"`
	...
}

The reverse relationship RelReverseOne:

type Profile struct {
	...
	User *User `orm:"reverse(one)"`
	...
}

One to many

RelForeignKey:

type Post struct {
	...
	User *User `orm:"rel(fk)"` // RelForeignKey relation
	...
}

The reverse relationship RelReverseMany:

type User struct {
	...
	Posts []*Post `orm:"reverse(many)"` // reverse relationship of fk
	...
}

Many to many

RelManyToMany:

type Post struct {
	...
	Tags []*Tag `orm:"rel(m2m)"` // ManyToMany relation
	...
}

The reverse relationship RelReverseMany:

type Tag struct {
	...
	Posts []*Post `orm:"reverse(many)"`
	...
}

In this example, by default the auto-generated table name is: post_tag. The name of the struct in which we have orm:"rel(m2m)" defines the first half part, the name of the struct in which we have orm:"reverse(many)" defines the other half. It respects the naming conversion convention we have seen in Naming conventions

rel_table / rel_through

This setting is for orm:"rel(m2m)" field:

rel_table       Set the auto-generated m2m connecting table name
rel_through     If you want to use custom m2m connecting table, set name by using this setting.
              Format: `project_path/current_package.ModelName`
              For example: `app/models.PostTagRel` PostTagRel table needs to have a relationship to Post table and Tag table.

If rel_table is set, rel_through is ignored.

You can set these as follows:

orm:"rel(m2m);rel_table(the_table_name)"

orm:"rel(m2m);rel_through(project_path/current_package.ModelName)"

on_delete

Set how to deal with field if related relationship is deleted:

cascade        cascade delete (default)
set_null       set to NULL. Need to set null = true
set_default    set to default value. Need to set default value.
do_nothing     do nothing. ignore.
type User struct {
	...
	Profile *Profile `orm:"null;rel(one);on_delete(set_null)"`
	...
}
type Profile struct {
	...
	User *User `orm:"reverse(one)"`
	...
}

// Set User.Profile to NULL while deleting Profile

Examples of on_delete

type User struct {
    Id int
    Name string
}

type Post struct {
    Id int
    Title string
    User *User `orm:"rel(fk)"`
}

Assume Post -> User is ManyToOne relationship by foreign key.

o.Filter("Id", 1).Delete()

This will delete User with Id 1 and all his Posts.

If you don’t want to delete the Posts, you need to set set_null

type Post struct {
    Id int
    Title string
    User *User `orm:"rel(fk);null;on_delete(set_null)"`
}

In this case, only set related Post.user_id to NULL while deleting.

Usually for performance purposes, it doesn’t matter to have redundant data. The massive deletion is the real problem

type Post struct {
    Id int
    Title string
    User *User `orm:"rel(fk);null;on_delete(do_nothing)"`
}

So just don’t change Post (ignore it) while deleting User.

Model fields mapping with database type

Here is the recommended database type mapping. It’s also the standard for table generation.

All the fields are NOT NULL by default.

MySQL

go mysql
int, int32 - set as auto or name is Id integer AUTO_INCREMENT
int64 - set as auto or name isId bigint AUTO_INCREMENT
uint, uint32 - set as auto or name is Id integer unsigned AUTO_INCREMENT
uint64 - set as auto or name is Id bigint unsigned AUTO_INCREMENT
bool bool
string - default size 255 varchar(size)
string - set type(char) char(size)
string - set type(text) longtext
time.Time - set type as date date
time.Time datetime
byte tinyint unsigned
rune integer
int integer
int8 tinyint
int16 smallint
int32 integer
int64 bigint
uint integer unsigned
uint8 tinyint unsigned
uint16 smallint unsigned
uint32 integer unsigned
uint64 bigint unsigned
float32 double precision
float64 double precision
float64 - set digits and decimals numeric(digits, decimals)

Sqlite3

go sqlite3
int, int32, int64, uint, uint32, uint64 - set as auto or name is Id integer AUTOINCREMENT
bool bool
string - default size 255 varchar(size)
string - set type(char) character(size)
string - set type(text) text
time.Time - set type as date date
time.Time datetime
byte tinyint unsigned
rune integer
int integer
int8 tinyint
int16 smallint
int32 integer
int64 bigint
uint integer unsigned
uint8 tinyint unsigned
uint16 smallint unsigned
uint32 integer unsigned
uint64 bigint unsigned
float32 real
float64 real
float64 - set digits and decimals decimal

PostgreSQL

go postgres
int, int32, int64, uint, uint32, uint64 - set as auto or name is Id serial
bool bool
string - if not set size default text varchar(size)
string - set type(char) char(size)
string - set type(text) text
string - set type(json) json
string - set type(jsonb) jsonb
time.Time - set type as date date
time.Time timestamp with time zone
byte smallint CHECK(“column” >= 0 AND “column” <= 255)
rune integer
int integer
int8 smallint CHECK(“column” >= -127 AND “column” <= 128)
int16 smallint
int32 integer
int64 bigint
uint bigint CHECK(“column” >= 0)
uint8 smallint CHECK(“column” >= 0 AND “column” <= 255)
uint16 integer CHECK(“column” >= 0)
uint32 bigint CHECK(“column” >= 0)
uint64 bigint CHECK(“column” >= 0)
float32 double precision
float64 double precision
float64 - set digits and decimals numeric(digits, decimals)

Relational fields

It’s field type depends on related primary key.

  • RelForeignKey
  • RelOneToOne
  • RelManyToMany
  • RelReverseOne
  • RelReverseMany