男神鹏:golang gorm 安装以及基础使用

1. 安装

 

go get -u github.com/jinzhu/gorm

2.声明module

 
  1. type User struct {
  2. gorm.Model
  3. Name string
  4. Age sql.NullInt64
  5. Birthday *time.Time
  6. Email string `gorm:"type:varchar(100);unique_index"`
  7. Role string `gorm:"size:255"` // 设置属性长度 255
  8. MemberNumber *string `gorm:"unique;not null"` //设置唯一并且非空
  9. Num int `gorm:"AUTO_INCREMENT"` //设置自增
  10. Address string `gorm:"index:addr"` //给字段address创建索引,名’addr’
  11. IgnoreMe int `gorm:"-"` // 忽略这个属性
  12. }

gorm.Model 包含如下属性: ID, CreatedAt, UpdatedAt, DeletedAt.

  1. // gorm.Model 定义
  2. type Model struct {
  3. ID uint `gorm:"primary_key"`
  4. CreatedAt time.Time
  5. UpdatedAt time.Time
  6. DeletedAt *time.Time
  7. }

GORM使用字段名为ID作为默认主键。

  1. type User struct {
  2. ID string
  3. Name string
  4. }
  5. //设置AnimalID作为主键
  6. type Animal struct {
  7. AnimalID int64 `gorm:"primary_key"`
  8. Name string
  9. Age int64
  10. }

在声明模型时,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.表名是结构体名称的复数形式

 
  1. type User struct {
  2. }
  3. 其默认表名为users

可以设置表名为自定义名称。

  1. func (User) TableName() string {
  2. return "profiles"
  3. }

如果不想使用这个复数形式,可以设置为单数,传true即可。

  1. db.SingularTable(true)

也可以这样定义:

  1. db.Table("users").CreateTable(&User{})

使用user的结构创建表名为users。

5. 时间戳

 

CreatedAt
一条记录第一次被创建的时候会修改该值。

  1. // will set `CreatedAt` to current time
  2. db.Create(&user)
  3. // To change its value, you could use `Update`
  4. db.Model(&user).Update("CreatedAt", time.Now())

UpdatedAt
当这条记录被修改的时候,会修改该字段。

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

DeletedAt
对于具有deleted_at字段的模型,当对该实例调用Delete时,不会真正从数据库中删除它,而是将其DeletedAt字段设置为当前时间

6.连接数据库

 

要连接到数据库,需要先导入数据库的驱动程序。

  1. import _ github.com/go-sql-driver/mysql

GORM包装了一些驱动程序,以便更容易记住导入路径。因此您可以使用以下命令导入mysql驱动程序:

  1. import _ "github.com/jinzhu/gorm/dialects/mysql"
  2. // import _ "github.com/jinzhu/gorm/dialects/postgres"
  3. // import _ "github.com/jinzhu/gorm/dialects/sqlite"
  4. // import _ "github.com/jinzhu/gorm/dialects/mssql"

下面主要讲下MySQL
注意:
为了正确地处理time.time,需要将parseTime作为一个参数。
为了完全支持UTF-8编码,需要将charset=utf8更改为charset=utf8mb4。

  1. import (
  2. "github.com/jinzhu/gorm"
  3. _ "github.com/jinzhu/gorm/dialects/mysql"
  4. )
  5. func main() {
  6. db, err := gorm.Open("mysql", "user:password@(localhost)/dbname?charset=utf8&parseTime=True&loc=Local")
  7. defer db.Close()
  8. }

7. Create

 
  1. user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
  2. db.NewRecord(user) // => 当主键为空时返回true
  3. db.Create(&user)
  4. db.NewRecord(user) // => user创建后返回false

默认值:

  1. type Animal struct {
  2. ID int64
  3. Name string `gorm:"default:'galeone'"`
  4. Age int64
  5. }

然后插入的SQL将排除那些没有值或零的字段

  1. var animal = Animal{Age: 99, Name: ""}
  2. db.Create(&animal)
  3. // INSERT INTO animals("age") values('99');
  4. // SELECT name from animals WHERE ID=111; // the returning primary key is 111
  5. // animal.Name => 'galeone'

注意:
所有具有零值的字段(如0、“”或其他零值)都不会保存到数据库中,而是使用其默认值。如果要避免这种情况,请考虑使用指针类型

  1. // Use pointer value
  2. type User struct {
  3. gorm.Model
  4. Name string
  5. Age *int `gorm:"default:18"`
  6. }
  7. // Use scanner/valuer
  8. type User struct {
  9. gorm.Model
  10. Name string
  11. Age sql.NullInt64 `gorm:"default:18"`
  12. }

使用钩子
如果要在BeforeCreate钩子中更新字段的值,可以使用scope.SetColumn,例如:

  1. func (user *User) BeforeCreate(scope *gorm.Scope) error {
  2. scope.SetColumn("ID", uuid.New())
  3. return nil
  4. }



8. Query

 
  1. // Get first record, order by primary key
  2. db.First(&user)
  3. //// SELECT * FROM users ORDER BY id LIMIT 1;
  4. // Get one record, no specified order
  5. db.Take(&user)
  6. //// SELECT * FROM users LIMIT 1;
  7. // Get last record, order by primary key
  8. db.Last(&user)
  9. //// SELECT * FROM users ORDER BY id DESC LIMIT 1;
  10. // Get all records
  11. db.Find(&users)
  12. //// SELECT * FROM users;
  13. // Get record with primary key (only works for integer primary key)
  14. db.First(&user, 10)
  15. //// SELECT * FROM users WHERE id = 10;

9. Where

 

原始sql

  1. // Get first matched record
  2. db.Where("name = ?", "jinzhu").First(&user)
  3. //// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;
  4. // Get all matched records
  5. db.Where("name = ?", "jinzhu").Find(&users)
  6. //// SELECT * FROM users WHERE name = 'jinzhu';
  7. // <>
  8. db.Where("name <> ?", "jinzhu").Find(&amp;users)
  9. //// SELECT * FROM users WHERE name <> 'jinzhu';
  10. // IN
  11. db.Where("name IN (?)", []string{"jinzhu", "jinzhu 2"}).Find(&amp;users)
  12. //// SELECT * FROM users WHERE name in ('jinzhu','jinzhu 2');
  13. // LIKE
  14. db.Where("name LIKE ?", "%jin%").Find(&amp;users)
  15. //// SELECT * FROM users WHERE name LIKE '%jin%';
  16. // AND
  17. db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&amp;users)
  18. //// SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22;
  19. // Time
  20. db.Where("updated_at > ?", lastWeek).Find(&amp;users)
  21. //// SELECT * FROM users WHERE updated_at > '2000-01-01 00:00:00';
  22. // BETWEEN
  23. db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&amp;users)
  24. //// SELECT * FROM users WHERE created_at BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';

10. Struct & Map

 
  1. // Struct
  2. db.Where(&User{Name: "jinzhu", Age: 20}).First(&amp;user)
  3. //// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 ORDER BY id LIMIT 1;
  4. // Map
  5. db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
  6. //// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;
  7. // Slice of primary keys
  8. db.Where([]int64{20, 21, 22}).Find(&users)
  9. //// SELECT * FROM users WHERE id IN (20, 21, 22);

注意:
当使用struct进行查询时,GORM将只使用那些字段具有非零值的查询,这意味着如果字段的值为0、’’、false或其他零值,则不会使用它来构建查询条件,例如:

  1. db.Where(&User{Name: "jinzhu", Age: 0}).Find(&users)
  2. //// SELECT * FROM users WHERE name = "jinzhu";

11. 添加额外查询项

 
  1. db.Set("gorm:query_option", "FOR UPDATE").First(&user, 10)
  2. //// SELECT * FROM users WHERE id = 10 FOR UPDATE;

12. FirstOrInit

 

获取第一个匹配的记录,或使用给定条件初始化新记录(仅适用于结构、map)

  1. // Unfound
  2. db.FirstOrInit(&amp;user, User{Name: "non_existing"})
  3. //// user -> User{Name: "non_existing"}
  4. // Found
  5. db.Where(User{Name: "Jinzhu"}).FirstOrInit(&amp;user)
  6. //// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
  7. db.FirstOrInit(&amp;user, map[string]interface{}{"name": "jinzhu"})
  8. //// user -> User{Id: 111, Name: "Jinzhu", Age: 20}

13. Attrs

 

如果找不到记录,则使用参数初始化结构

  1. // Unfound
  2. db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrInit(&amp;user)
  3. //// SELECT * FROM USERS WHERE name = 'non_existing' ORDER BY id LIMIT 1;
  4. //// user -> User{Name: "non_existing", Age: 20}
  5. db.Where(User{Name: "non_existing"}).Attrs("age", 20).FirstOrInit(&amp;user)
  6. //// SELECT * FROM USERS WHERE name = 'non_existing' ORDER BY id LIMIT 1;
  7. //// user -> User{Name: "non_existing", Age: 20}
  8. // Found
  9. db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 30}).FirstOrInit(&amp;user)
  10. //// SELECT * FROM USERS WHERE name = jinzhu' ORDER BY id LIMIT 1;
  11. //// user -> User{Id: 111, Name: "Jinzhu", Age: 20}

14. Assign

 

将参数赋给结构,不管是否找到它。

  1. // Unfound
  2. db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrInit(&amp;user)
  3. //// user -> User{Name: "non_existing", Age: 20}
  4. // Found
  5. db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 30}).FirstOrInit(&amp;user)
  6. //// SELECT * FROM USERS WHERE name = jinzhu' ORDER BY id LIMIT 1;
  7. //// user -> User{Id: 111, Name: "Jinzhu", Age: 30}

15. FirstOrCreate

 

获取第一个匹配的记录,或使用给定条件创建一个新记录(仅适用于结构、映射条件)。

  1. // Unfound
  2. db.FirstOrCreate(&user, User{Name: "non_existing"})
  3. //// INSERT INTO "users" (name) VALUES ("non_existing");
  4. //// user -> User{Id: 112, Name: "non_existing"}
  5. // Found
  6. db.Where(User{Name: "Jinzhu"}).FirstOrCreate(&user)
  7. //// user -> User{Id: 111, Name: "Jinzhu"}

16.高级查询

 

SubQuery

  1. db.Where("amount > ?", db.Table("orders").Select("AVG(amount)").Where("state = ?", "paid").SubQuery()).Find(&orders)
  2. // SELECT * FROM "orders" WHERE "orders"."deleted_at" IS NULL AND (amount > (SELECT AVG(amount) FROM "orders" WHERE (state = 'paid')));

Select

  1. db.Select("name, age").Find(&users)
  2. //// SELECT name, age FROM users;
  3. db.Select([]string{"name", "age"}).Find(&users)
  4. //// SELECT name, age FROM users;
  5. db.Table("users").Select("COALESCE(age,?)", 42).Rows()
  6. //// SELECT COALESCE(age,'42') FROM users;

Order
指定从数据库检索记录时的顺序,将reorder(第二个参数)设置为true以覆盖定义的条件。

  1. db.Order("age desc, name").Find(&users)
  2. //// SELECT * FROM users ORDER BY age desc, name;
  3. // Multiple orders
  4. db.Order("age desc").Order("name").Find(&users)
  5. //// SELECT * FROM users ORDER BY age desc, name;
  6. // ReOrder
  7. db.Order("age desc").Find(&users1).Order("age", true).Find(&users2)
  8. //// SELECT * FROM users ORDER BY age desc; (users1)
  9. //// SELECT * FROM users ORDER BY age; (users2)

Limit
指定要检索的最大记录数。

  1. db.Limit(3).Find(&users)
  2. //// SELECT * FROM users LIMIT 3;
  3. // Cancel limit condition with -1
  4. db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
  5. //// SELECT * FROM users LIMIT 10; (users1)
  6. //// SELECT * FROM users; (users2)

Offset
指定开始返回记录之前要跳过的记录数。

  1. db.Offset(3).Find(&users)
  2. //// SELECT * FROM users OFFSET 3;
  3. // Cancel offset condition with -1
  4. db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
  5. //// SELECT * FROM users OFFSET 10; (users1)
  6. //// SELECT * FROM users; (users2)

Count
获取模型的记录数。

  1. db.Where("name = ?", "jinzhu").Or("name = ?", "jinzhu 2").Find(&users).Count(&count)
  2. //// SELECT * from USERS WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (users)
  3. //// SELECT count(*) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (count)
  4. db.Model(&User{}).Where("name = ?", "jinzhu").Count(&count)
  5. //// SELECT count(*) FROM users WHERE name = 'jinzhu'; (count)
  6. db.Table("deleted_users").Count(&amp;count)
  7. //// SELECT count(*) FROM deleted_users;
  8. db.Table("deleted_users").Select("count(distinct(name))").Count(&count)
  9. //// SELECT count( distinct(name) ) FROM deleted_users; (count)

Group &Having

  1. rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()
  2. for rows.Next() {
  3. ...
  4. }
  5. rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Rows()
  6. for rows.Next() {
  7. ...
  8. }
  9. type Result struct {
  10. Date time.Time
  11. Total int64
  12. }
  13. db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&amp;results)

Joins

  1. rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
  2. for rows.Next() {
  3. ...
  4. }
  5. db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)
  6. // multiple joins with parameter
  7. db.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。

  1. var ages []int64
  2. db.Find(&users).Pluck("age", &ages)
  3. var names []string
  4. db.Model(&User{}).Pluck("name", &names)
  5. db.Table("deleted_users").Pluck("name", &names)
  6. // Requesting more than one column? Do it like this:
  7. db.Select("name, age").Find(&users)

Scan
将结果扫描到另一个结构中。

  1. type Result struct {
  2. Name string
  3. Age int
  4. }
  5. var result Result
  6. db.Table("users").Select("name, age").Where("name = ?", "Antonio").Scan(&result)
  7. // Raw SQL
  8. db.Raw("SELECT name, age FROM users WHERE name = ?", "Antonio").Scan(&result)

Update
修改所有属性。Save将在执行更新SQL时包含所有字段,即使没有更改。

 

  1. db.First(&user)
  2. user.Name = "jinzhu2"
  3. user.Age = 100
  4. db.Save(&user)
  5. //// 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。

  1. // Update single attribute if it is changed
  2. db.Model(&user).Update("name", "hello")
  3. //// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;
  4. // Update single attribute with combined conditions
  5. db.Model(&user).Where("active = ?", true).Update("name", "hello")
  6. //// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;
  7. // Update multiple attributes with `map`, will only update those changed fields
  8. db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
  9. //// UPDATE users SET name='hello', age=18, actived=false, updated_at='2013-11-17 21:34:10' WHERE id=111;
  10. // Update multiple attributes with `struct`, will only update those changed &amp; non blank fields
  11. db.Model(&user).Updates(User{Name: "hello", Age: 18})
  12. //// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;
  13. // WARNING when update with struct, GORM will only update those fields that with non blank value
  14. // For below Update, nothing will be updated as "", 0, false are blank values of their types
  15. db.Model(&user).Updates(User{Name: "", Age: 0, Actived: false})

修改列不用钩子
以上更新操作将执行模型的BeforeUpdate、AfterUpdate方法,更新其UpdatedAt时间戳,更新时保存其关联,如果不想调用它们,可以使用UpdateColumn、UpdateColumns。

  1. // Update single attribute, similar with `Update`
  2. db.Model(&user).UpdateColumn("name", "hello")
  3. //// UPDATE users SET name='hello' WHERE id = 111;
  4. // Update multiple attributes, similar with `Updates`
  5. db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18})
  6. //// UPDATE users SET name='hello', age=18 WHERE id = 111;

批量修改
批量更新时不会运行钩子。

  1. db.Table("users").Where("id IN (?)", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 18})
  2. //// UPDATE users SET name='hello', age=18 WHERE id IN (10, 11);
  3. // Update with struct only works with none zero values, or use map[string]interface{}
  4. db.Model(User{}).Updates(User{Name: "hello", Age: 18})
  5. //// UPDATE users SET name='hello', age=18;
  6. // Get updated records count with `RowsAffected`
  7. db.Model(User{}).Updates(User{Name: "hello", Age: 18}).RowsAffected

使用 SQL **表达式

  1. DB.Model(&product).Update("price", gorm.Expr("price * ? + ?", 2, 100))
  2. //// UPDATE "products" SET "price" = price * '2' + '100', "updated_at" = '2013-11-17 21:34:10' WHERE "id" = '2';
  3. DB.Model(&product).Updates(map[string]interface{}{"price": gorm.Expr("price * ? + ?", 2, 100)})
  4. //// UPDATE "products" SET "price" = price * '2' + '100', "updated_at" = '2013-11-17 21:34:10' WHERE "id" = '2';
  5. DB.Model(&product).UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))
  6. //// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = '2';
  7. DB.Model(&product).Where("quantity > 1").UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))
  8. //// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = '2' AND quantity > 1;

使用钩子更改值
如果要使用BeforeUpdate、BeforeSave更改挂钩中的更新值,可以使用scope.SetColumn,例如:

  1. func (user *User) BeforeSave(scope *gorm.Scope) (err error) {
  2. if pw, err := bcrypt.GenerateFromPassword(user.Password, 0); err == nil {
  3. scope.SetColumn("EncryptedPassword", pw)
  4. }
  5. }

Delete
如果一个模型有一个DeletedAt字段,它将自动获得一个软删除能力!调用Delete时,不会从数据库中永久删除记录;相反,DeletedAt的值将设置为当前时间。

  1. db.Delete(&amp;user)
  2. //// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
  3. // Batch Delete
  4. db.Where("age = ?", 20).Delete(&amp;User{})
  5. //// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
  6. // Soft deleted records will be ignored when query them
  7. db.Where("age = 20").Find(&amp;user)
  8. //// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
  9. // Find soft deleted records with Unscoped
  10. db.Unscoped().Where("age = 20").Find(&amp;users)
  11. //// SELECT * FROM users WHERE age = 20;

永久删除记录

  1. // Delete record permanently with Unscoped
  2. db.Unscoped().Delete(&order)
  3. //// DELETE FROM orders WHERE id=10;

Belongs To
归属于关联与另一个模型建立一对一的连接,这样声明模型的每个实例都“属于”另一个模型的一个实例。
例如,如果应用程序包含用户和配置文件,并且每个配置文件都可以指定给一个用户。

  1. type User struct {
  2. gorm.Model
  3. Name string
  4. }
  5. // `Profile` belongs to `User`, `UserID` is the foreign key
  6. type Profile struct {
  7. gorm.Model
  8. UserID int
  9. User User
  10. Name string
  11. }

外键
若要定义“属于”关系,外键必须存在,默认外键使用所有者的类型名及其主键。
对于上面的示例,要定义属于用户的模型,外键应该是UserID。
GORM提供了一种自定义外键的方法,例如:

  1. type User struct {
  2. gorm.Model
  3. Name string
  4. }
  5. type Profile struct {
  6. gorm.Model
  7. Name string
  8. User User `gorm:"foreignkey:UserRefer"` // use UserRefer as foreign key
  9. UserRefer uint
  10. }

关联外键
对于归属关系,GORM通常使用所有者的主键作为外键的值,例如,它是用户的ID。
将配置文件分配给用户时,GORM会将用户的ID保存到配置文件的UserID字段中。可以使用标记关联外键进行更改,例如:

  1. type User struct {
  2. gorm.Model
  3. Refer string
  4. Name string
  5. }
  6. type Profile struct {
  7. gorm.Model
  8. Name string
  9. User User `gorm:"association_foreignkey:Refer"` // use Refer as association foreign key
  10. UserRefer string
  11. }

使用 belong to

  1. db.Model(&user).Related(&profile)
  2. //// SELECT * FROM profiles WHERE user_id = 111; // 111 is user's ID

ManyToMany

**Foreign Keys

  1. type CustomizePerson struct {
  2. IdPerson string `gorm:"primary_key:true"`
  3. Accounts []CustomizeAccount `gorm:"many2many:PersonAccount;association_foreignkey:idAccount;foreignkey:idPerson"`
  4. }
  5. type CustomizeAccount struct {
  6. IdAccount string `gorm:"primary_key:true"`
  7. Name string
  8. }



它将为这两个结构创建多个关系,并将它们的关系保存到联接表personAccount带有外键的customize_person_id_person和customize_account。

Jointable ForeignKey
如果要更改联接表的外键,可以使用标记关联。

  1. type CustomizePerson struct {
  2. IdPerson string `gorm:"primary_key:true"`
  3. Accounts []CustomizeAccount `gorm:"many2many:PersonAccount;foreignkey:idPerson;association_foreignkey:idAccount;association_jointable_foreignkey:account_id;jointable_foreignkey:person_id;"`
  4. }
  5. type CustomizeAccount struct {
  6. IdAccount string `gorm:"primary_key:true"`
  7. Name string
  8. }



Self-Referencing
要定义自引用的many2many关系,必须在联接表中更改关联的外键。要使其与使用结构名称及其主键生成的源外键不同,例如:

  1. type People struct {
  2. gorm.Model
  3. Friends []*People `gorm:"many2many:friendships;association_jointable_foreignkey:friend_id"`
  4. }

GORM将创建一个具有外键people_id和friend_id的联接表,并使用它保存用户的自引用关系。

17. 错误处理

 

Error Handling
GORM中的错误处理不同于惯用的Go代码,因为它的API是可链接的,但是仍然易于实现。
如果发生任何错误,GORM将设置*GORM.DB的错误字段,可以这样检查:

  1. f err := db.Where("name = ?", "jinzhu").First(&user).Error; err != nil {
  2. // error handling...
  3. }

RecordNotFound Error
GORM提供了处理RecordNotFound错误的快捷方式。如果有几个错误,它将检查其中是否有一个是RecordNotFound错误。

  1. // Check if returns RecordNotFound error
  2. db.Where("name = ?", "hello world").First(&user).RecordNotFound()
  3. if db.Model(&user).Related(&amp;credit_card).RecordNotFound() {
  4. // record not found
  5. }
  6. if err := db.Where("name = ?", "jinzhu").First(&user).Error; gorm.IsRecordNotFoundError(err) {
  7. // record not found
  8. }

18 事务

 

GORM默认情况下在事务中执行单个创建、更新、删除操作,以确保数据库数据的完整性。如果要将多个create、update、delete视为一个原子操作,则为此进行事务处理。

  1. func CreateAnimals(db *gorm.DB) error {
  2. return db.Transaction(func(tx *gorm.DB) error {
  3. // do some database operations in the transaction (use 'tx' from this point, not 'db')
  4. if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {
  5. // return any error will rollback
  6. return err
  7. }
  8. if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {
  9. return err
  10. }
  11. // return nil will commit
  12. return nil
  13. })
  14. }

19. Migration

 

自动迁移架构,使架构保持最新。
注意:自动迁移将只创建表、缺少列和缺少索引,并且不会更改现有列的类型或删除未使用的列以保护数据。

  1. db.AutoMigrate(&User{})
  2. db.AutoMigrate(&User{}, &amp;Product{}, &Order{})
  3. // Add table suffix when create tables
  4. db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{})

20. Schema Methods

 

判断表是否存在。

  1. // Check model `User`'s table exists or not
  2. db.HasTable(&User{})
  3. // Check table `users` exists or not
  4. db.HasTable("users")

创建表。

  1. // Create table for model `User`
  2. db.CreateTable(&User{})
  3. // will append "ENGINE=InnoDB" to the SQL statement when creating table `users`
  4. db.Set("gorm:table_options", "ENGINE=InnoDB").CreateTable(&User{})

删除表。

  1. // Drop model `User`'s table
  2. db.DropTable(&User{})
  3. // Drop table `users`
  4. db.DropTable("users")
  5. // Drop model's `User`'s table and table `products`
  6. db.DropTableIfExists(&User{}, "products")

修改列。

  1. // change column description's data type to `text` for model `User`
  2. db.Model(&User{}).ModifyColumn("description", "text")

添加索引。

  1. // Add index for columns `name` with given name `idx_user_name`
  2. db.Model(&User{}).AddIndex("idx_user_name", "name")
  3. // Add index for columns `name`, `age` with given name `idx_user_name_age`
  4. db.Model(&User{}).AddIndex("idx_user_name_age", "name", "age")
  5. // Add unique index
  6. db.Model(&User{}).AddUniqueIndex("idx_user_name", "name")
  7. // Add unique index for multiple columns
  8. db.Model(&User{}).AddUniqueIndex("idx_user_name_age", "name", "age")

删除索引。

  1. // Remove index
  2. db.Model(&User{}).RemoveIndex("idx_user_name")

复合主键。
将多个字段设置为主键以启用复合主键。

  1. type Product struct {
  2. ID string `gorm:"primary_key"`
  3. LanguageCode string `gorm:"primary_key"`
  4. Code string
  5. Name string
  6. }

注意,带有primary_key标记的整数字段在默认情况下是自动递增的。这可能导致多个自动递增的整数主键,而不是单个复合主键。
要创建包含int的复合主键,需要关闭int字段的自动递增:

    1. type Product struct {
    2. CategoryID uint64 `gorm:"primary_key;auto_increment:false"`
    3. TypeID uint64 `gorm:"primary_key;auto_increment:false"`
    4. }
posted @ 2020-11-27 16:23  男神鹏●詹姆斯  阅读(1526)  评论(0编辑  收藏  举报