男神鹏:golang gorm 安装以及基础使用
1. 安装
go get -u github.com/jinzhu/gorm
2.声明module
type User struct {gorm.ModelName stringAge sql.NullInt64Birthday *time.TimeEmail string `gorm:"type:varchar(100);unique_index"`Role string `gorm:"size:255"` // 设置属性长度 255MemberNumber *string `gorm:"unique;not null"` //设置唯一并且非空Num int `gorm:"AUTO_INCREMENT"` //设置自增Address string `gorm:"index:addr"` //给字段address创建索引,名’addr’IgnoreMe int `gorm:"-"` // 忽略这个属性}
gorm.Model 包含如下属性: ID, CreatedAt, UpdatedAt, DeletedAt.
// gorm.Model 定义type Model struct {ID uint `gorm:"primary_key"`CreatedAt time.TimeUpdatedAt time.TimeDeletedAt *time.Time}
GORM使用字段名为ID作为默认主键。
type User struct {ID stringName string}//设置AnimalID作为主键type Animal struct {AnimalID int64 `gorm:"primary_key"`Name stringAge int64}
在声明模型时,tags是可选的。GORM支持以下tags。
| **Tag** | **Description** |
|---|---|
| Column | Specifies column name |
| Type | Specifies column data type |
| Size | Specifies column size, default 255 |
| PRIMARY_KEY | Specifies column as primary key |
| UNIQUE | Specifies column as unique |
| DEFAULT | Specifies column default value |
| PRECISION | Specifies column precision |
| NOT NULL | Specifies column as NOT NULL |
| AUTO_INCREMENT | Specifies column auto incrementable or not |
| INDEX | Create index with or without name, same name creates composite indexes |
| UNIQUE_INDEX | Like INDEX, create unique index |
| EMBEDDED | Set struct as embedded |
| EMBEDDED_PREFIX | Set embedded struct’s prefix name |
| - | Ignore this fields |
3. 关联的结构标记
4.表名是结构体名称的复数形式
type User struct {}其默认表名为users
可以设置表名为自定义名称。
func (User) TableName() string {return "profiles"}
如果不想使用这个复数形式,可以设置为单数,传true即可。
db.SingularTable(true)
也可以这样定义:
db.Table("users").CreateTable(&User{})
使用user的结构创建表名为users。
5. 时间戳
CreatedAt
一条记录第一次被创建的时候会修改该值。
// will set `CreatedAt` to current timedb.Create(&user)// To change its value, you could use `Update`db.Model(&user).Update("CreatedAt", time.Now())
UpdatedAt
当这条记录被修改的时候,会修改该字段。
// will set `UpdatedAt` to current timedb.Save(&user)// will set `UpdatedAt` to current timedb.Model(&user).Update("name", "jinzhu")
DeletedAt
对于具有deleted_at字段的模型,当对该实例调用Delete时,不会真正从数据库中删除它,而是将其DeletedAt字段设置为当前时间
6.连接数据库
要连接到数据库,需要先导入数据库的驱动程序。
import _ ”github.com/go-sql-driver/mysql“
GORM包装了一些驱动程序,以便更容易记住导入路径。因此您可以使用以下命令导入mysql驱动程序:
import _ "github.com/jinzhu/gorm/dialects/mysql"// import _ "github.com/jinzhu/gorm/dialects/postgres"// import _ "github.com/jinzhu/gorm/dialects/sqlite"// import _ "github.com/jinzhu/gorm/dialects/mssql"
下面主要讲下MySQL
注意:
为了正确地处理time.time,需要将parseTime作为一个参数。
为了完全支持UTF-8编码,需要将charset=utf8更改为charset=utf8mb4。
import ("github.com/jinzhu/gorm"_ "github.com/jinzhu/gorm/dialects/mysql")func main() {db, err := gorm.Open("mysql", "user:password@(localhost)/dbname?charset=utf8&parseTime=True&loc=Local")defer db.Close()}
7. Create
user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}db.NewRecord(user) // => 当主键为空时返回truedb.Create(&user)db.NewRecord(user) // => user创建后返回false
默认值:
type Animal struct {ID int64Name string `gorm:"default:'galeone'"`Age int64}
然后插入的SQL将排除那些没有值或零的字段
var animal = Animal{Age: 99, Name: ""}db.Create(&animal)// INSERT INTO animals("age") values('99');// SELECT name from animals WHERE ID=111; // the returning primary key is 111// animal.Name => 'galeone'
注意:
所有具有零值的字段(如0、“”或其他零值)都不会保存到数据库中,而是使用其默认值。如果要避免这种情况,请考虑使用指针类型
// Use pointer valuetype User struct {gorm.ModelName stringAge *int `gorm:"default:18"`}// Use scanner/valuertype User struct {gorm.ModelName stringAge sql.NullInt64 `gorm:"default:18"`}
使用钩子
如果要在BeforeCreate钩子中更新字段的值,可以使用scope.SetColumn,例如:
func (user *User) BeforeCreate(scope *gorm.Scope) error {scope.SetColumn("ID", uuid.New())return nil}
8. Query
// Get first record, order by primary keydb.First(&user)//// SELECT * FROM users ORDER BY id LIMIT 1;// Get one record, no specified orderdb.Take(&user)//// SELECT * FROM users LIMIT 1;// Get last record, order by primary keydb.Last(&user)//// SELECT * FROM users ORDER BY id DESC LIMIT 1;// Get all recordsdb.Find(&users)//// SELECT * FROM users;// Get record with primary key (only works for integer primary key)db.First(&user, 10)//// SELECT * FROM users WHERE id = 10;
9. Where
原始sql
// Get first matched recorddb.Where("name = ?", "jinzhu").First(&user)//// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;// Get all matched recordsdb.Where("name = ?", "jinzhu").Find(&users)//// SELECT * FROM users WHERE name = 'jinzhu';// <>db.Where("name <> ?", "jinzhu").Find(&users)//// SELECT * FROM users WHERE name <> 'jinzhu';// INdb.Where("name IN (?)", []string{"jinzhu", "jinzhu 2"}).Find(&users)//// SELECT * FROM users WHERE name in ('jinzhu','jinzhu 2');// LIKEdb.Where("name LIKE ?", "%jin%").Find(&users)//// SELECT * FROM users WHERE name LIKE '%jin%';// ANDdb.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)//// SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22;// Timedb.Where("updated_at > ?", lastWeek).Find(&users)//// SELECT * FROM users WHERE updated_at > '2000-01-01 00:00:00';// BETWEENdb.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)//// SELECT * FROM users WHERE created_at BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';
10. Struct & Map
// Structdb.Where(&User{Name: "jinzhu", Age: 20}).First(&user)//// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 ORDER BY id LIMIT 1;// Mapdb.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)//// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;// Slice of primary keysdb.Where([]int64{20, 21, 22}).Find(&users)//// SELECT * FROM users WHERE id IN (20, 21, 22);
注意:
当使用struct进行查询时,GORM将只使用那些字段具有非零值的查询,这意味着如果字段的值为0、’’、false或其他零值,则不会使用它来构建查询条件,例如:
db.Where(&User{Name: "jinzhu", Age: 0}).Find(&users)//// SELECT * FROM users WHERE name = "jinzhu";
11. 添加额外查询项
db.Set("gorm:query_option", "FOR UPDATE").First(&user, 10)//// SELECT * FROM users WHERE id = 10 FOR UPDATE;
12. FirstOrInit
获取第一个匹配的记录,或使用给定条件初始化新记录(仅适用于结构、map)
// Unfounddb.FirstOrInit(&user, User{Name: "non_existing"})//// user -> User{Name: "non_existing"}// Founddb.Where(User{Name: "Jinzhu"}).FirstOrInit(&user)//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}db.FirstOrInit(&user, map[string]interface{}{"name": "jinzhu"})//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
13. Attrs
如果找不到记录,则使用参数初始化结构
// Unfounddb.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrInit(&user)//// SELECT * FROM USERS WHERE name = 'non_existing' ORDER BY id LIMIT 1;//// user -> User{Name: "non_existing", Age: 20}db.Where(User{Name: "non_existing"}).Attrs("age", 20).FirstOrInit(&user)//// SELECT * FROM USERS WHERE name = 'non_existing' ORDER BY id LIMIT 1;//// user -> User{Name: "non_existing", Age: 20}// Founddb.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 30}).FirstOrInit(&user)//// SELECT * FROM USERS WHERE name = jinzhu' ORDER BY id LIMIT 1;//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
14. Assign
将参数赋给结构,不管是否找到它。
// Unfounddb.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrInit(&user)//// user -> User{Name: "non_existing", Age: 20}// Founddb.Where(User{Name: "Jinzhu"}).Assign(User{Age: 30}).FirstOrInit(&user)//// SELECT * FROM USERS WHERE name = jinzhu' ORDER BY id LIMIT 1;//// user -> User{Id: 111, Name: "Jinzhu", Age: 30}
15. FirstOrCreate
获取第一个匹配的记录,或使用给定条件创建一个新记录(仅适用于结构、映射条件)。
// Unfounddb.FirstOrCreate(&user, User{Name: "non_existing"})//// INSERT INTO "users" (name) VALUES ("non_existing");//// user -> User{Id: 112, Name: "non_existing"}// Founddb.Where(User{Name: "Jinzhu"}).FirstOrCreate(&user)//// user -> User{Id: 111, Name: "Jinzhu"}
16.高级查询
SubQuery
db.Where("amount > ?", db.Table("orders").Select("AVG(amount)").Where("state = ?", "paid").SubQuery()).Find(&orders)// SELECT * FROM "orders" WHERE "orders"."deleted_at" IS NULL AND (amount > (SELECT AVG(amount) FROM "orders" WHERE (state = 'paid')));
Select
db.Select("name, age").Find(&users)//// SELECT name, age FROM users;db.Select([]string{"name", "age"}).Find(&users)//// SELECT name, age FROM users;db.Table("users").Select("COALESCE(age,?)", 42).Rows()//// SELECT COALESCE(age,'42') FROM users;
Order
指定从数据库检索记录时的顺序,将reorder(第二个参数)设置为true以覆盖定义的条件。
db.Order("age desc, name").Find(&users)//// SELECT * FROM users ORDER BY age desc, name;// Multiple ordersdb.Order("age desc").Order("name").Find(&users)//// SELECT * FROM users ORDER BY age desc, name;// ReOrderdb.Order("age desc").Find(&users1).Order("age", true).Find(&users2)//// SELECT * FROM users ORDER BY age desc; (users1)//// SELECT * FROM users ORDER BY age; (users2)
Limit
指定要检索的最大记录数。
db.Limit(3).Find(&users)//// SELECT * FROM users LIMIT 3;// Cancel limit condition with -1db.Limit(10).Find(&users1).Limit(-1).Find(&users2)//// SELECT * FROM users LIMIT 10; (users1)//// SELECT * FROM users; (users2)
Offset
指定开始返回记录之前要跳过的记录数。
db.Offset(3).Find(&users)//// SELECT * FROM users OFFSET 3;// Cancel offset condition with -1db.Offset(10).Find(&users1).Offset(-1).Find(&users2)//// SELECT * FROM users OFFSET 10; (users1)//// SELECT * FROM users; (users2)
Count
获取模型的记录数。
db.Where("name = ?", "jinzhu").Or("name = ?", "jinzhu 2").Find(&users).Count(&count)//// SELECT * from USERS WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (users)//// SELECT count(*) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (count)db.Model(&User{}).Where("name = ?", "jinzhu").Count(&count)//// SELECT count(*) FROM users WHERE name = 'jinzhu'; (count)db.Table("deleted_users").Count(&count)//// SELECT count(*) FROM deleted_users;db.Table("deleted_users").Select("count(distinct(name))").Count(&count)//// SELECT count( distinct(name) ) FROM deleted_users; (count)
Group &Having
rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()for rows.Next() {...}rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Rows()for rows.Next() {...}type Result struct {Date time.TimeTotal int64}db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&results)
Joins
rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()for rows.Next() {...}db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)// multiple joins with parameterdb.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Joins("JOIN credit_cards ON credit_cards.user_id = users.id").Where("credit_cards.number = ?", "411111111111").Find(&user)
Pluck
将模型中的单个列作为映射查询,如果要查询多个列,则应改用Scan。
var ages []int64db.Find(&users).Pluck("age", &ages)var names []stringdb.Model(&User{}).Pluck("name", &names)db.Table("deleted_users").Pluck("name", &names)// Requesting more than one column? Do it like this:db.Select("name, age").Find(&users)
Scan
将结果扫描到另一个结构中。
type Result struct {Name stringAge int}var result Resultdb.Table("users").Select("name, age").Where("name = ?", "Antonio").Scan(&result)// Raw SQLdb.Raw("SELECT name, age FROM users WHERE name = ?", "Antonio").Scan(&result)
Update
修改所有属性。Save将在执行更新SQL时包含所有字段,即使没有更改。
db.First(&user)user.Name = "jinzhu2"user.Age = 100db.Save(&user)//// UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;
更新更改的字段
如果只想更新已更改的字段,可以使用update,Updates。
// Update single attribute if it is changeddb.Model(&user).Update("name", "hello")//// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;// Update single attribute with combined conditionsdb.Model(&user).Where("active = ?", true).Update("name", "hello")//// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;// Update multiple attributes with `map`, will only update those changed fieldsdb.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})//// UPDATE users SET name='hello', age=18, actived=false, updated_at='2013-11-17 21:34:10' WHERE id=111;// Update multiple attributes with `struct`, will only update those changed & non blank fieldsdb.Model(&user).Updates(User{Name: "hello", Age: 18})//// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;// WARNING when update with struct, GORM will only update those fields that with non blank value// For below Update, nothing will be updated as "", 0, false are blank values of their typesdb.Model(&user).Updates(User{Name: "", Age: 0, Actived: false})
修改列不用钩子
以上更新操作将执行模型的BeforeUpdate、AfterUpdate方法,更新其UpdatedAt时间戳,更新时保存其关联,如果不想调用它们,可以使用UpdateColumn、UpdateColumns。
// Update single attribute, similar with `Update`db.Model(&user).UpdateColumn("name", "hello")//// UPDATE users SET name='hello' WHERE id = 111;// Update multiple attributes, similar with `Updates`db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18})//// UPDATE users SET name='hello', age=18 WHERE id = 111;
批量修改
批量更新时不会运行钩子。
db.Table("users").Where("id IN (?)", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 18})//// UPDATE users SET name='hello', age=18 WHERE id IN (10, 11);// Update with struct only works with none zero values, or use map[string]interface{}db.Model(User{}).Updates(User{Name: "hello", Age: 18})//// UPDATE users SET name='hello', age=18;// Get updated records count with `RowsAffected`db.Model(User{}).Updates(User{Name: "hello", Age: 18}).RowsAffected
使用 SQL **表达式
DB.Model(&product).Update("price", gorm.Expr("price * ? + ?", 2, 100))//// UPDATE "products" SET "price" = price * '2' + '100', "updated_at" = '2013-11-17 21:34:10' WHERE "id" = '2';DB.Model(&product).Updates(map[string]interface{}{"price": gorm.Expr("price * ? + ?", 2, 100)})//// UPDATE "products" SET "price" = price * '2' + '100', "updated_at" = '2013-11-17 21:34:10' WHERE "id" = '2';DB.Model(&product).UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))//// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = '2';DB.Model(&product).Where("quantity > 1").UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))//// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = '2' AND quantity > 1;
使用钩子更改值
如果要使用BeforeUpdate、BeforeSave更改挂钩中的更新值,可以使用scope.SetColumn,例如:
func (user *User) BeforeSave(scope *gorm.Scope) (err error) {if pw, err := bcrypt.GenerateFromPassword(user.Password, 0); err == nil {scope.SetColumn("EncryptedPassword", pw)}}
Delete
如果一个模型有一个DeletedAt字段,它将自动获得一个软删除能力!调用Delete时,不会从数据库中永久删除记录;相反,DeletedAt的值将设置为当前时间。
db.Delete(&user)//// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;// Batch Deletedb.Where("age = ?", 20).Delete(&User{})//// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;// Soft deleted records will be ignored when query themdb.Where("age = 20").Find(&user)//// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;// Find soft deleted records with Unscopeddb.Unscoped().Where("age = 20").Find(&users)//// SELECT * FROM users WHERE age = 20;
永久删除记录
// Delete record permanently with Unscopeddb.Unscoped().Delete(&order)//// DELETE FROM orders WHERE id=10;
Belongs To
归属于关联与另一个模型建立一对一的连接,这样声明模型的每个实例都“属于”另一个模型的一个实例。
例如,如果应用程序包含用户和配置文件,并且每个配置文件都可以指定给一个用户。
type User struct {gorm.ModelName string}// `Profile` belongs to `User`, `UserID` is the foreign keytype Profile struct {gorm.ModelUserID intUser UserName string}
外键
若要定义“属于”关系,外键必须存在,默认外键使用所有者的类型名及其主键。
对于上面的示例,要定义属于用户的模型,外键应该是UserID。
GORM提供了一种自定义外键的方法,例如:
type User struct {gorm.ModelName string}type Profile struct {gorm.ModelName stringUser User `gorm:"foreignkey:UserRefer"` // use UserRefer as foreign keyUserRefer uint}
关联外键
对于归属关系,GORM通常使用所有者的主键作为外键的值,例如,它是用户的ID。
将配置文件分配给用户时,GORM会将用户的ID保存到配置文件的UserID字段中。可以使用标记关联外键进行更改,例如:
type User struct {gorm.ModelRefer stringName string}type Profile struct {gorm.ModelName stringUser User `gorm:"association_foreignkey:Refer"` // use Refer as association foreign keyUserRefer string}
使用 belong to
db.Model(&user).Related(&profile)//// SELECT * FROM profiles WHERE user_id = 111; // 111 is user's ID
ManyToMany
**Foreign Keys
type CustomizePerson struct {IdPerson string `gorm:"primary_key:true"`Accounts []CustomizeAccount `gorm:"many2many:PersonAccount;association_foreignkey:idAccount;foreignkey:idPerson"`}type CustomizeAccount struct {IdAccount string `gorm:"primary_key:true"`Name string}
它将为这两个结构创建多个关系,并将它们的关系保存到联接表personAccount带有外键的customize_person_id_person和customize_account。
Jointable ForeignKey
如果要更改联接表的外键,可以使用标记关联。
type CustomizePerson struct {IdPerson string `gorm:"primary_key:true"`Accounts []CustomizeAccount `gorm:"many2many:PersonAccount;foreignkey:idPerson;association_foreignkey:idAccount;association_jointable_foreignkey:account_id;jointable_foreignkey:person_id;"`}type CustomizeAccount struct {IdAccount string `gorm:"primary_key:true"`Name string}
Self-Referencing
要定义自引用的many2many关系,必须在联接表中更改关联的外键。要使其与使用结构名称及其主键生成的源外键不同,例如:
type People struct {gorm.ModelFriends []*People `gorm:"many2many:friendships;association_jointable_foreignkey:friend_id"`}
GORM将创建一个具有外键people_id和friend_id的联接表,并使用它保存用户的自引用关系。
17. 错误处理
Error Handling
GORM中的错误处理不同于惯用的Go代码,因为它的API是可链接的,但是仍然易于实现。
如果发生任何错误,GORM将设置*GORM.DB的错误字段,可以这样检查:
f err := db.Where("name = ?", "jinzhu").First(&user).Error; err != nil {// error handling...}
RecordNotFound Error
GORM提供了处理RecordNotFound错误的快捷方式。如果有几个错误,它将检查其中是否有一个是RecordNotFound错误。
// Check if returns RecordNotFound errordb.Where("name = ?", "hello world").First(&user).RecordNotFound()if db.Model(&user).Related(&credit_card).RecordNotFound() {// record not found}if err := db.Where("name = ?", "jinzhu").First(&user).Error; gorm.IsRecordNotFoundError(err) {// record not found}
18 事务
GORM默认情况下在事务中执行单个创建、更新、删除操作,以确保数据库数据的完整性。如果要将多个create、update、delete视为一个原子操作,则为此进行事务处理。
func CreateAnimals(db *gorm.DB) error {return db.Transaction(func(tx *gorm.DB) error {// do some database operations in the transaction (use 'tx' from this point, not 'db')if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {// return any error will rollbackreturn err}if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {return err}// return nil will commitreturn nil})}
19. Migration
自动迁移架构,使架构保持最新。
注意:自动迁移将只创建表、缺少列和缺少索引,并且不会更改现有列的类型或删除未使用的列以保护数据。
db.AutoMigrate(&User{})db.AutoMigrate(&User{}, &Product{}, &Order{})// Add table suffix when create tablesdb.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{})
20. Schema Methods
判断表是否存在。
// Check model `User`'s table exists or notdb.HasTable(&User{})// Check table `users` exists or notdb.HasTable("users")
创建表。
// Create table for model `User`db.CreateTable(&User{})// will append "ENGINE=InnoDB" to the SQL statement when creating table `users`db.Set("gorm:table_options", "ENGINE=InnoDB").CreateTable(&User{})
删除表。
// Drop model `User`'s tabledb.DropTable(&User{})// Drop table `users`db.DropTable("users")// Drop model's `User`'s table and table `products`db.DropTableIfExists(&User{}, "products")
修改列。
// change column description's data type to `text` for model `User`db.Model(&User{}).ModifyColumn("description", "text")
添加索引。
// Add index for columns `name` with given name `idx_user_name`db.Model(&User{}).AddIndex("idx_user_name", "name")// Add index for columns `name`, `age` with given name `idx_user_name_age`db.Model(&User{}).AddIndex("idx_user_name_age", "name", "age")// Add unique indexdb.Model(&User{}).AddUniqueIndex("idx_user_name", "name")// Add unique index for multiple columnsdb.Model(&User{}).AddUniqueIndex("idx_user_name_age", "name", "age")
删除索引。
// Remove indexdb.Model(&User{}).RemoveIndex("idx_user_name")
复合主键。
将多个字段设置为主键以启用复合主键。
type Product struct {ID string `gorm:"primary_key"`LanguageCode string `gorm:"primary_key"`Code stringName string}
注意,带有primary_key标记的整数字段在默认情况下是自动递增的。这可能导致多个自动递增的整数主键,而不是单个复合主键。
要创建包含int的复合主键,需要关闭int字段的自动递增:
type Product struct {CategoryID uint64 `gorm:"primary_key;auto_increment:false"`TypeID uint64 `gorm:"primary_key;auto_increment:false"`}

浙公网安备 33010602011771号