Определение модели GORM и миграция базы данных для программирования баз данных Golang

Go

Оригинальный автор, публичный аккаунт [программист чтение], прошу обратить внимание на паблик-аккаунт, просьба указывать источник перепечатываемой статьи.

При разработке приложения, вообще говоря, мы сначала проектируем таблицу данных, а затем используем язык разработки для построения соответствующей модели данных.Однако то, о чем мы будем говорить сегодня, — это процесс обратной операции, то есть, как определитьGORMмодель данных фреймворка, а затем, выполнивGROMПриложение, написанное во фрейме, использует определенную модель данных для создания соответствующей таблицы данных в базе данных.

Итак, нам нужно поговорить о том, как определениеGORMмодель данных.

определение модели

Как правило, мы говоримGROMОпределение модели относится к определению структуры, представляющей таблицу данных (struct), то мы можем использоватьGROMПлатформа может отображать структуру в таблицу данных соответствующей реляционной базы данных или запрашивать данные в таблице данных для заполнения структуры, как показано ниже, мы определяем именованныйPostструктура.

type Post struct {
    PostId    int
    Uid       int
    Title     string
    Content   string
    Type      int
    CreatedAt time.Time
    UpdatedAt time.Time
}

Создание структуры — это только первый шаг, но давайте не будем беспокоиться о том, как сначала создать таблицу данных.Сначала мы должны понять правила сопоставления между структурой и таблицей данных.Основные моменты заключаются в следующем:

Struct tags

мы знаем,GoСтруктура языка поддерживает использованиеtagsРасширьте дополнительную информацию для каждого поля структуры, например, используя стандартную библиотеку.encoding/jsonпакет дляJSONПри кодировании можно использоватьtagsРасширение, которое кодирует дополнительную информацию.

GROMФреймворк имеет свойtagsконвенции, следующим образом:

Column	指定列名
Type	指定列数据类型
Size	指定列大小, 默认值255
PRIMARY_KEY	将列指定为主键
UNIQUE	将列指定为唯一
DEFAULT	指定列默认值
PRECISION   指定列精度
NOT NULL    将列指定为非 NULL
AUTO_INCREMENT  指定列是否为自增类型
INDEX   创建具有或不带名称的索引, 如果多个索引同名则创建复合索引
UNIQUE_INDEX    和 INDEX 类似,只不过创建的是唯一索引
EMBEDDED    将结构设置为嵌入
EMBEDDED_PREFIX 设置嵌入结构的前缀
-   忽略此字段

GROM также поддерживает некоторые соглашения тегов, связанные с таблицами данных.Когда у меня будет возможность поговорить об ассоциации таблиц данных GROM, я расскажу об этом.

Перечисленные выше теги, поддерживаемые GORM, удобны для настройки правил сопоставления между полями структуры и полями таблицы данных.В следующем коде мы даемPostНастройка структурыtagsРазвернуть следующим образом:

type Post struct {
    PostId    int    `gorm:"primary_key;auto_increment"`
    Uid       int    `gorm:"type:int;not null"`
    Title     string `gorm:"type:varchar(255);not null"`
    Content   string `gorm:"type:text;not null"`
    Type      uint8  `gorm:"type:tinyint;default 1;not null"`
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt time.Time
}

Из приведенного выше примера мы видим, чтоGORMОпределите формат тегов для полей модели данных, каждое поле может использовать несколько типовtagsИнформация, разделяйте теги точкой с запятой.

соглашение

Помимо вышеперечисленногоtagsВ дополнение к определению правил сопоставления между полями, когда Go Maps структуры в таблицах реляционных данных, он также имеет свой собственный набор конвенций, или конвенций, которые в основном следующие:

первичный ключ

Гром согласился, вообще в модели данныхIDПоля сопоставляются с первичным ключом таблицы данных, как определено ниже.TestModel,IDпервичный ключ,TestModelизIDТип данныхstring,еслиIDТип данныхint, GROM также установитAUTO_INCREMENT,использоватьIDстать автоматически увеличивающимся первичным ключом.

type TestModel struct{
    ID   int
    Name string
}

Конечно, мы также можем настроить имя поля первичного ключа, как указано выше.Postструктура, мы устанавливаемPostIdПоле является первичным ключом.Если мы определим другие поля как первичный ключ, то даже если все еще естьIDполе,GROMрамки не будутIDПоле используется как первичный ключ.

type Post struct {
    ID        int
    PostId    int    `gorm:"primary_key;auto_increment"`
    Uid       int    `gorm:"type:int;not null"`
    Title     string `gorm:"type:varchar(255);not null"`
    Content   string `gorm:"type:text;not null"`
    Type      uint8  `gorm:"type:tinyint;default 1;not null"`
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt time.Time
}

По этому мыPostдобавить один в структуруIDполе,PostIdПоле по-прежнему является первичным ключом, в данных используется следующееdesc postsРезультат, напечатанный оператором:

Правила сопоставления таблиц данных

Когда мы используем структуру для создания таблицы данных, имя таблицы данных по умолчанию соответствует множественной форме структуры в нижнем регистре, например структураPostСоответствующее имя таблицы данныхposts, Конечно, мы также можем указать имя таблицы данных, соответствующее структуре, вместо использования значения по умолчанию.

добавить в структуруTableName()метод, с помощью которого вы можете вернуть имя пользовательской таблицы данных следующим образом:

//指定Post结构体对应的数据表为my_posts
func (p Post) TableName() string{
    return "my_posts"
}
префикс таблицы данных

Помимо указания имени таблицы данных, мы также можем переопределитьgorm.DefaultTableNameHandlerЭта переменная, чтобы можно было указать единый префикс таблицы данных для всех таблиц данных, выглядит следующим образом:

gorm.DefaultTableNameHandler = func (db *gorm.DB, defaultTableName string) string  {
    return "tb_" + defaultTableName;
}

В этом случае через структуруPostИмя созданной таблицы данныхtb_posts.

Правила сопоставления полей

Правила сопоставления структуры имени к таблице данных на таблицу данных по умолчанию Поле данных правила сопоставления по умолчанию - это разделенная таблица. Начните с заглавной буквы каждого слова подчеркиваются как имя сложной структуры, а структура поля, следующим образом:

type Prize struct {
	ID int
	PrizeName string
}

структура вышеPrizeсерединаPrizeNameТаблица данных, соответствующая полю,prize_name, но мы ставимPrizeNameизменить наPrizename, соответствующее имя поля таблицы данныхprizename, это связано с тем, что разделяются только слова в начале поля в верхнем регистре.

Конечно, мы также можем определить поле структурыtagsРасширенная информация, так что правила отображения из полей структуры в поля таблицы данных находятся вtagsопределено в.

отслеживание времени

Ранее мы говорили, что если в структуре есть имяIDполе, тоGORMФреймворк будет использовать это поле как первичный ключ таблицы данных, кроме того, если структура имеетCreatedAt,UpdatedAt,DeletedAtЕсли эти поляGROMФреймворк также выполнит некоторую специальную обработку, правила следующие:

CreatedAt:新增数据表记录的时候,会自动写入这个字段。
UpdatedAt:更新数据表记录的时候,会自动更新这个字段。
DeletedAt:当执行软删除的时候,会自动更新这个字段,表示删除时间
gorm.Model

Так как если структура имеетID,CreatedAt,UpdatedAt,DeletedAtЭти более общие поля,GORMФреймворк будет автоматически обрабатывать эти поля, поэтому, если нашей структуре нужны эти поля, мы можем напрямую встроить их в пользовательскую структуру.gorm.Modelструктура,gorm.ModelСтруктура выглядит следующим образом:

type Model struct {
    ID        uint `gorm:"primary_key"`
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt *time.Time `sql:"index"`
}

Итак, если мы находимся в структуреPrizeвстроенный вgorm.Model,следующее:

type Prize struct{
    gorm.Model
    Name string
}

В этом случае структураPrizeСодержит пять полей.

миграция базы данных

Мы говорим о миграции базы данных, то есть благодаря использованиюGROMПредоставляется набор методов, в соответствии с определенными правилами модели данных, создание, удаление таблиц данных и другие операции, то есть операции DDL в базе данных.

GORMПредоставляет методы для выполнения операций DDL в базах данных, главным образом в следующих категориях:

Работа с таблицей данных

//根据模型自动创建数据表
func (s *DB) AutoMigrate(values ...interface{}) *DB 

//根据模型创建数据表
func (s *DB) CreateTable(models ...interface{}) *DB

//删除数据表,相当于drop table语句
func (s *DB) DropTable(values ...interface{}) *DB 

//相当于drop table if exsist 语句
func (s *DB) DropTableIfExists(values ...interface{}) *DB 

//根据模型判断数据表是否存在
func (s *DB) HasTable(value interface{}) bool 

операция столбца

//删除数据表字段
func (s *DB) DropColumn(column string) *DB

//修改数据表字段的数据类型
func (s *DB) ModifyColumn(column string, typ string) *DB

индексная операция

//添加外键
func (s *DB) AddForeignKey(field string, dest string, onDelete string, onUpdate string) *DB

//给数据表字段添加索引
func (s *DB) AddIndex(indexName string, columns ...string) *DB

//给数据表字段添加唯一索引
func (s *DB) AddUniqueIndex(indexName string, columns ...string) *DB

Пример простого кода переноса данных

Обратите внимание, что в следующем примере программыdbПеременное представлениеgorm.DBObject, процесс его инициализации можете сослаться на мою предыдущую статью.

type User struct {
    Id       int   //对应数据表的自增id
    Username string
    Password string
    Email    string
    Phone    string
}

func main(){
    db.AutoMigrate(&Post{},&User{})//创建posts和users数据表

    db.CreateTable(&Post{})//创建posts数据表
    
    db.Set("gorm:table_options", "ENGINE=InnoDB").CreateTable(&Post{})//创建posts表时指存在引擎
    
    db.DropTable(&Post{},"users")//删除posts和users表数据表
    
    db.DropTableIfExists(&Post{},"users")//删除前会判断posts和users表是否存在
    
    //先判断users表是否存在,再删除users表
    if db.HasTable("users") {
        db.DropTable("users")
    }
    
    //删除数据表字段
    db.Model(&Post{}).DropColumn("id")
    
    //修改字段数据类型
    db.Model(&Post{}).ModifyColumn("id","varchar(255)")
    
    //建立posts与users表之间的外键关联
    db.Model(&Post{}).AddForeignKey("uid", "users(id)", "RESTRICT", "RESTRICT")
    
    //给posts表的title字段添加索引
    db.Model(&Post{}).AddIndex("index_title","title")
    
    //给users表的phone字段添加唯一索引
    db.Model(&User{}).AddUniqueIndex("index_phone","phone")
}

резюме

Вы спросите, а не достаточно ли создавать и удалять таблицы данных прямо в БД? Зачем эти операции в приложении? Потому что иногда мы не можем войти в систему базы данных или нам нужно разработать приложение, которое может управлять базой данных.GROMЭти возможности миграции базы данных, предоставляемые платформой, пригодятся.


Ваше внимание — самое большое поощрение на моем писательском пути!