• 男神鹏: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. }
  • 相关阅读:
    C++公有派生
    Android学习笔记(十二)——实战:制作一个聊天界面
    Android学习笔记(十一)——ListView的使用(下)
    Android学习笔记(十)——ListView的使用(上)
    Android学习笔记(九)——布局和控件的自定义
    【Leetcode周赛】从contest-41开始。(一般是10个contest写一篇文章)
    算法群模拟面试记录
    【Leetcode周赛】从contest-51开始。(一般是10个contest写一篇文章)
    【服务端开发-杂】REST 和 Graphql
    【Kickstart】2017 Round (Practice ~ G)
  • 原文地址:https://www.cnblogs.com/lyp0626/p/14048772.html
Copyright © 2020-2023  润新知