# Models

- Model Definition
- Conventions
  - `gorm.Model` struct
  - Table name is the pluralized version of struct name
  - Column name is the snake case of field's name
  - Field `ID` as primary key
  - Field `CreatedAt` used to store record's created time
  - Use `UpdatedAt` used to store record's updated time
  - Use `DeletedAt` to store record's deleted time if field exists

## Model Definition

    type User struct {
        gorm.Model
        Birthday     time.Time
        Age          int
        Name         string  `gorm:"size:255"` // Default size for string is 255, reset it with this tag
        Num          int     `gorm:"AUTO_INCREMENT"`

        CreditCard        CreditCard      // One-To-One relationship (has one - use CreditCard's UserID as foreign key)
        Emails            []Email         // One-To-Many relationship (has many - use Email's UserID as foreign key)

        BillingAddress    Address         // One-To-One relationship (belongs to - use BillingAddressID as foreign key)
        BillingAddressID  sql.NullInt64

        ShippingAddress   Address         // One-To-One relationship (belongs to - use ShippingAddressID as foreign key)
        ShippingAddressID int

        IgnoreMe          int `gorm:"-"`   // Ignore this field
        Languages         []Language `gorm:"many2many:user_languages;"` // Many-To-Many relationship, 'user_languages' is join table
    }

    type Email struct {
        ID      int
        UserID  int     `gorm:"index"` // Foreign key (belongs to), tag `index` will create index for this column
        Email   string  `gorm:"type:varchar(100);unique_index"` // `type` set sql type, `unique_index` will create unique index for this column
        Subscribed bool
    }

    type Address struct {
        ID       int
        Address1 string         `gorm:"not null;unique"` // Set field as not nullable and unique
        Address2 string         `gorm:"type:varchar(100);unique"`
        Post     sql.NullString `gorm:"not null"`
    }

    type Language struct {
        ID   int
        Name string `gorm:"index:idx_name_code"` // Create index with name, and will create combined index if find other fields defined same name
        Code string `gorm:"index:idx_name_code"` // `unique_index` also works
    }

    type CreditCard struct {
        gorm.Model
        UserID  uint
        Number  string
    }

## Conventions

### `gorm.Model` struct

Base model definition `gorm.Model`, including fields `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt`, you could embed it in your model, or only write those fields you want

    // Base Model's definition
    type Model struct {
      ID        uint `gorm:"primary_key"`
      CreatedAt time.Time
      UpdatedAt time.Time
      DeletedAt *time.Time
    }

    // Add fields `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt`
    type User struct {
      gorm.Model
      Name string
    }

    // Only need field `ID`, `CreatedAt`
    type User struct {
      ID        uint
      CreatedAt time.Time
      Name      string
    }

### Table name is the pluralized version of struct name

    type User struct {} // default table name is `users`

    // set User's table name to be `profiles
    func (User) TableName() string {
      return "profiles"
    }

    func (u User) TableName() string {
        if u.Role == "admin" {
            return "admin_users"
        } else {
            return "users"
        }
    }

    // Disable table name's pluralization globally
    db.SingularTable(true) // if set this to true, `User`'s default table name will be `user`, table name setted with `TableName` won't be affected

### Column name is the snake case of field's name

    type User struct {
      ID uint             // column name will be `id`
      Name string         // column name will be `name`
      Birthday time.Time  // column name will be `birthday`
      CreatedAt time.Time // column name will be `created_at`
    }

    // Overriding Column Name
    type Animal struct {
        AnimalId    int64     `gorm:"column:beast_id"`         // set column name to `beast_id`
        Birthday    time.Time `gorm:"column:day_of_the_beast"` // set column name to `day_of_the_beast`
        Age         int64     `gorm:"column:age_of_the_beast"` // set column name to `age_of_the_beast`
    }

### Field `ID` as primary key

    type User struct {
      ID   uint  // field named `ID` will be the default primary field
      Name string
    }

    // Set a field to be primary field with tag `primary_key`
    type Animal struct {
      AnimalId int64 `gorm:"primary_key"` // set AnimalId to be primary key
      Name     string
      Age      int64
    }

### Field `CreatedAt` used to store record's created time

Create records having `CreatedAt` field will set it to current time.

    db.Create(&user) // will set `CreatedAt` to current time

    // To change its value, you could use `Update`
    db.Model(&user).Update("CreatedAt", time.Now())

### Use `UpdatedAt` used to store record's updated time

Save records having `UpdatedAt` field will set it to current time.

    db.Save(&user) // will set `UpdatedAt` to current time
    db.Model(&user).Update("name", "jinzhu") // will set `UpdatedAt` to current time

### Use `DeletedAt` to store record's deleted time if field exists

Delete records having `DeletedAt` field, it won't be deleted from database, but only set field `DeletedAt`'s value to current time, and the record is not findable when querying, refer Soft Delete