男神鵬: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. }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM