Update Documents

This commit is contained in:
Jinzhu 2016-02-26 21:53:28 +08:00
parent 9d0203847c
commit 547210665d
32 changed files with 673 additions and 800 deletions

View File

@ -1,13 +1,31 @@
# Summary # Summary
* [GORM Guides](http://github.com/jinzhu/gorm)
* [Getting Started with GORM](README.md) * [Getting Started with GORM](README.md)
{% for path, chapter in book.chapters %} * [Database](database.md)
* [{{ chapter.name }}]({{ path }}) * [Database Connection](database.md#connecting-to-a-database)
{% for section in chapter.sections %} * [Migration](database.md#migration)
* [{{ section.name }}]({{ section.path }}) * [Models](models.md)
{% if section["sections"] %}{% for subsection in section.sections %} * [Model Defination](models.md#model-defination),
* [{{ subsection.name }}]({{ subsection.path }}) * [Naming Conventions & Overriding](models.md#conventions-overriding-conventions),
{% endfor %}{% endif %}{% endfor %} * [Associations](associations.md)
{% endfor %} * [Belongs To](associations.md#belongs-to)
* [Has One](associations.md#has-one)
* [Has Many](associations.md#has-many)
* [Many To Many](associations.md#many-to-many)
* [Polymorphism](associations.md#polymorphism)
* [Association Mode](associations.md#association-mode)
* [CRUD: Reading and Writing Data](curd.md)
* [Create](curd.md#create),
* [Query](curd.md#query),
* [Preloading (Eager Loading)](curd.md#preloading),
* [Update](curd.md#update),
* [Delete / Soft Delete](curd.md#delete)
* [Callbacks](callbacks.md)
* [Advanced Usage](advanced.md)
* [Error Handling](advanced.md#error-handling)
* [Transactions](advanced.md#transactions)
* [Raw SQL & SQL Builder](advanced.md#sql-builder)
* [Composite Primary Key](advanced.md#compose-primary-key)
* [Overriding Logger](advanced.md#logger)
* [Development](development.md)
* [Write Plugins](development.md#callbacks)

149
doc/advanced.md Normal file
View File

@ -0,0 +1,149 @@
# Advanced Usage
<!-- toc -->
## Error Handling
```go
query := db.Where("name = ?", "jinzhu").First(&user)
query := db.First(&user).Limit(10).Find(&users)
// query.Error will return the last happened error
// So you could do error handing in your application like this:
if err := db.Where("name = ?", "jinzhu").First(&user).Error; err != nil {
// error handling...
}
// RecordNotFound
// If no record found when you query data, gorm will return RecordNotFound error, you could check it like this:
db.Where("name = ?", "hello world").First(&User{}).Error == gorm.RecordNotFound
// Or use the shortcut method
db.Where("name = ?", "hello world").First(&user).RecordNotFound()
if db.Model(&user).Related(&credit_card).RecordNotFound() {
// no credit card found error handling
}
```
## Transactions
To perform a set of operations within a transaction, the general flow is as below.
The database handle returned from ``` db.Begin() ``` should be used for all operations within the transaction.
(Note that all individual save and delete operations are run in a transaction by default.)
```go
// begin
tx := db.Begin()
// do some database operations (use 'tx' from this point, not 'db')
tx.Create(...)
...
// rollback in case of error
tx.Rollback()
// Or commit if all is ok
tx.Commit()
```
### A Specific Example
```go
func CreateAnimals(db *gorm.DB) err {
tx := db.Begin()
// Note the use of tx as the database handle once you are within a transaction
if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {
tx.Rollback()
return err
}
if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {
tx.Rollback()
return err
}
tx.Commit()
return nil
}
```
## Raw SQL
```go
db.Exec("DROP TABLE users;")
db.Exec("UPDATE orders SET shipped_at=? WHERE id IN (?)", time.Now, []int64{11,22,33})
```
## Row & Rows
It is even possible to get query result as `*sql.Row` or `*sql.Rows`
```go
row := db.Table("users").Where("name = ?", "jinzhu").Select("name, age").Row() // (*sql.Row)
row.Scan(&name, &age)
rows, err := db.Model(&User{}).Where("name = ?", "jinzhu").Select("name, age, email").Rows() // (*sql.Rows, error)
defer rows.Close()
for rows.Next() {
...
rows.Scan(&name, &age, &email)
...
}
// Raw SQL
rows, err := db.Raw("select name, age, email from users where name = ?", "jinzhu").Rows() // (*sql.Rows, error)
defer rows.Close()
for rows.Next() {
...
rows.Scan(&name, &age, &email)
...
}
```
### Scan Rows
```go
rows, err := db.Model(&User{}).Where("name = ?", "jinzhu").Select("name, age, email").Rows() // (*sql.Rows, error)
defer rows.Close()
for rows.Next() {
var user User
db.ScanRows(rows, &user)
// do something
}
```
## Composite Primary Key
```go
type Product struct {
ID string `gorm:"primary_key"`
LanguageCode string `gorm:"primary_key"`
}
```
## Logger
Gorm has built-in logger support
```go
// Enable Logger
db.LogMode(true)
// Diable Logger
db.LogMode(false)
// Debug a single operation
db.Debug().Where("name = ?", "jinzhu").First(&User{})
```
![logger](https://raw.github.com/jinzhu/gorm/master/doc/logger.png)
### Customize Logger
```go
// Refer gorm's default logger for how to: https://github.com/jinzhu/gorm/blob/master/logger.go#files
db.SetLogger(gorm.Logger{revel.TRACE})
db.SetLogger(log.New(os.Stdout, "\r\n", 0))
```

View File

@ -1,10 +0,0 @@
# Advanced Usage
{% for section in book.chapters["advanced/advanced.md"].sections %}
* [**{{section.name}}**](../{{section.path}})
{% if section["sections"] %}{% for subsection in section.sections %}
* [**{{ subsection.name }}**]({{ subsection.path }})
{% endfor %}{% endif %}
{% endfor %}

View File

@ -1,8 +0,0 @@
# Composite Primary Key
```go
type Product struct {
ID string `gorm:"primary_key"`
LanguageCode string `gorm:"primary_key"`
}
```

View File

@ -1,22 +0,0 @@
# Error Handling
```go
query := db.Where("name = ?", "jinzhu").First(&user)
query := db.First(&user).Limit(10).Find(&users)
// query.Error will return the last happened error
// So you could do error handing in your application like this:
if err := db.Where("name = ?", "jinzhu").First(&user).Error; err != nil {
// error handling...
}
// RecordNotFound
// If no record found when you query data, gorm will return RecordNotFound error, you could check it like this:
db.Where("name = ?", "hello world").First(&User{}).Error == gorm.RecordNotFound
// Or use the shortcut method
db.Where("name = ?", "hello world").First(&user).RecordNotFound()
if db.Model(&user).Related(&credit_card).RecordNotFound() {
// no credit card found error handling
}
```

View File

@ -1,24 +0,0 @@
# Logger
Gorm has built-in logger support
```go
// Enable Logger
db.LogMode(true)
// Diable Logger
db.LogMode(false)
// Debug a single operation
db.Debug().Where("name = ?", "jinzhu").First(&User{})
```
![logger](https://raw.github.com/jinzhu/gorm/master/doc/logger.png)
### Customize Logger
```go
// Refer gorm's default logger for how to: https://github.com/jinzhu/gorm/blob/master/logger.go#files
db.SetLogger(gorm.Logger{revel.TRACE})
db.SetLogger(log.New(os.Stdout, "\r\n", 0))
```

View File

@ -1,38 +0,0 @@
# Query Chain
```go
db.First(&first_article).Count(&total_count).Limit(10).Find(&first_page_articles).Offset(10).Find(&second_page_articles)
//// SELECT * FROM articles LIMIT 1; (first_article)
//// SELECT count(*) FROM articles; (total_count)
//// SELECT * FROM articles LIMIT 10; (first_page_articles)
//// SELECT * FROM articles LIMIT 10 OFFSET 10; (second_page_articles)
db.Where("created_at > ?", "2013-10-10").Find(&cancelled_orders, "state = ?", "cancelled").Find(&shipped_orders, "state = ?", "shipped")
//// SELECT * FROM orders WHERE created_at > '2013/10/10' AND state = 'cancelled'; (cancelled_orders)
//// SELECT * FROM orders WHERE created_at > '2013/10/10' AND state = 'shipped'; (shipped_orders)
// Use variables to keep query chain
todays_orders := db.Where("created_at > ?", "2013-10-29")
cancelled_orders := todays_orders.Where("state = ?", "cancelled")
shipped_orders := todays_orders.Where("state = ?", "shipped")
// Search with shared conditions for different tables
db.Where("product_name = ?", "fancy_product").Find(&orders).Find(&shopping_carts)
//// SELECT * FROM orders WHERE product_name = 'fancy_product'; (orders)
//// SELECT * FROM carts WHERE product_name = 'fancy_product'; (shopping_carts)
// Search with shared conditions from different tables with specified table
db.Where("mail_type = ?", "TEXT").Find(&users1).Table("deleted_users").Find(&users2)
//// SELECT * FROM users WHERE mail_type = 'TEXT'; (users1)
//// SELECT * FROM deleted_users WHERE mail_type = 'TEXT'; (users2)
// FirstOrCreate example
db.Where("email = ?", "x@example.org").Attrs(User{RegisteredIp: "111.111.111.111"}).FirstOrCreate(&user)
//// SELECT * FROM users WHERE email = 'x@example.org';
//// INSERT INTO "users" (email,registered_ip) VALUES ("x@example.org", "111.111.111.111") // if record not found
```

View File

@ -1,45 +0,0 @@
## Raw SQL
```go
db.Exec("DROP TABLE users;")
db.Exec("UPDATE orders SET shipped_at=? WHERE id IN (?)", time.Now, []int64{11,22,33})
```
## Row & Rows
It is even possible to get query result as `*sql.Row` or `*sql.Rows`
```go
row := db.Table("users").Where("name = ?", "jinzhu").Select("name, age").Row() // (*sql.Row)
row.Scan(&name, &age)
rows, err := db.Model(&User{}).Where("name = ?", "jinzhu").Select("name, age, email").Rows() // (*sql.Rows, error)
defer rows.Close()
for rows.Next() {
...
rows.Scan(&name, &age, &email)
...
}
// Raw SQL
rows, err := db.Raw("select name, age, email from users where name = ?", "jinzhu").Rows() // (*sql.Rows, error)
defer rows.Close()
for rows.Next() {
...
rows.Scan(&name, &age, &email)
...
}
```
### Scan Rows
```go
rows, err := db.Model(&User{}).Where("name = ?", "jinzhu").Select("name, age, email").Rows() // (*sql.Rows, error)
defer rows.Close()
for rows.Next() {
var user User
db.ScanRows(rows, &user)
// do something
}
```

View File

@ -1,42 +0,0 @@
## Transactions
To perform a set of operations within a transaction, the general flow is as below.
The database handle returned from ``` db.Begin() ``` should be used for all operations within the transaction.
(Note that all individual save and delete operations are run in a transaction by default.)
```go
// begin
tx := db.Begin()
// do some database operations (use 'tx' from this point, not 'db')
tx.Create(...)
...
// rollback in case of error
tx.Rollback()
// Or commit if all is ok
tx.Commit()
```
### A Specific Example
```go
func CreateAnimals(db *gorm.DB) err {
tx := db.Begin()
// Note the use of tx as the database handle once you are within a transaction
if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {
tx.Rollback()
return err
}
if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {
tx.Rollback()
return err
}
tx.Commit()
return nil
}
```

150
doc/associations.md Normal file
View File

@ -0,0 +1,150 @@
# Associations
<!-- toc -->
## Belongs To
```go
// User belongs to a profile, ProfileID is the foreign key
type User struct {
gorm.Model
Profile Profile
ProfileID int
}
type Profile struct {
gorm.Model
Name string
}
db.Model(&user).Related(&profile)
//// SELECT * FROM profiles WHERE id = 111; // 111 is user's foreign key ProfileID
```
## Has One
```go
// User has one CreditCard, UserID is the foreign key
type User struct {
gorm.Model
CreditCard CreditCard
}
type CreditCard struct {
gorm.Model
UserID uint
Number string
}
var card CreditCard
db.Model(&user).Related(&card, "CreditCard")
//// SELECT * FROM credit_cards WHERE user_id = 123; // 123 is user's primary key
// CreditCard is user's field name, it means get user's CreditCard relations and fill it into variable card
// If the field name is same as the variable's type name, like above example, it could be omitted, like:
db.Model(&user).Related(&card)
```
## Has Many
```go
// User has many emails, UserID is the foreign key
type User struct {
gorm.Model
Emails []Email
}
type Email struct {
gorm.Model
Email string
UserID uint
}
db.Model(&user).Related(&emails)
//// SELECT * FROM emails WHERE user_id = 111; // 111 is user's primary key
```
## Many To Many
```go
// User has and belongs to many languages, use `user_languages` as join table
type User struct {
gorm.Model
Languages []Language `gorm:"many2many:user_languages;"`
}
type Language struct {
gorm.Model
Name string
}
db.Model(&user).Related(&languages)
//// SELECT * FROM "languages" INNER JOIN "user_languages" ON "user_languages"."language_id" = "languages"."id" WHERE "user_languages"."user_id" = 111
```
## Polymorphism
Supports polymorphic has-many and has-one associations.
```go
type Cat struct {
Id int
Name string
Toy Toy `gorm:"polymorphic:Owner;"`
}
type Dog struct {
Id int
Name string
Toy Toy `gorm:"polymorphic:Owner;"`
}
type Toy struct {
Id int
Name string
OwnerId int
OwnerType string
}
```
Note: polymorphic belongs-to and many-to-many are explicitly NOT supported, and will throw errors.
## Association Mode
Association Mode contains some helper methods to handle relationship things easily.
```go
// Start Association Mode
var user User
db.Model(&user).Association("Languages")
// `user` is the source, it need to be a valid record (contains primary key)
// `Languages` is source's field name for a relationship.
// If those conditions not matched, will return an error, check it with:
// db.Model(&user).Association("Languages").Error
// Query - Find out all related associations
db.Model(&user).Association("Languages").Find(&languages)
// Append - Append new associations for many2many, has_many, will replace current association for has_one, belongs_to
db.Model(&user).Association("Languages").Append([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Append(Language{Name: "DE"})
// Delete - Remove relationship between source & passed arguments, won't delete those arguments
db.Model(&user).Association("Languages").Delete([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Delete(languageZH, languageEN)
// Replace - Replace current associations with new one
db.Model(&user).Association("Languages").Replace([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Replace(Language{Name: "DE"}, languageEN)
// Count - Return the count of current associations
db.Model(&user).Association("Languages").Count()
// Clear - Remove relationship between source & current associations, won't delete those associations
db.Model(&user).Association("Languages").Clear()
```

View File

@ -1,40 +0,0 @@
# Association Mode
Association Mode contains some helper methods to handle relationship things easily.
```go
// Start Association Mode
var user User
db.Model(&user).Association("Languages")
// `user` is the source, it need to be a valid record (contains primary key)
// `Languages` is source's field name for a relationship.
// If those conditions not matched, will return an error, check it with:
// db.Model(&user).Association("Languages").Error
// Query - Find out all related associations
db.Model(&user).Association("Languages").Find(&languages)
// Append - Append new associations for many2many, has_many, will replace current association for has_one, belongs_to
db.Model(&user).Association("Languages").Append([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Append(Language{Name: "DE"})
// Delete - Remove relationship between source & passed arguments, won't delete those arguments
db.Model(&user).Association("Languages").Delete([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Delete(languageZH, languageEN)
// Replace - Replace current associations with new one
db.Model(&user).Association("Languages").Replace([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Replace(Language{Name: "DE"}, languageEN)
// Count - Return the count of current associations
db.Model(&user).Association("Languages").Count()
// Clear - Remove relationship between source & current associations, won't delete those associations
db.Model(&user).Association("Languages").Clear()
```

View File

@ -1,8 +0,0 @@
# Associations
{% for section in book.chapters["associations/associations.md"].sections %}
* [**{{section.name}}**](../{{section.path}})
{% if section["sections"] %}{% for subsection in section.sections %}
* [**{{ subsection.name }}**]({{ subsection.path }})
{% endfor %}{% endif %}
{% endfor %}

View File

@ -1,18 +0,0 @@
# Belongs To
```go
// User belongs to a profile, ProfileID is the foreign key
type User struct {
gorm.Model
Profile Profile
ProfileID int
}
type Profile struct {
gorm.Model
Name string
}
db.Model(&user).Related(&profile)
//// SELECT * FROM profiles WHERE id = 111; // 111 is user's foreign key ProfileID
```

View File

@ -1,18 +0,0 @@
# Has Many
```go
// User has many emails, UserID is the foreign key
type User struct {
gorm.Model
Emails []Email
}
type Email struct {
gorm.Model
Email string
UserID uint
}
db.Model(&user).Related(&emails)
//// SELECT * FROM emails WHERE user_id = 111; // 111 is user's primary key
```

View File

@ -1,22 +0,0 @@
# Has One
```go
// User has one CreditCard, UserID is the foreign key
type User struct {
gorm.Model
CreditCard CreditCard
}
type CreditCard struct {
gorm.Model
UserID uint
Number string
}
var card CreditCard
db.Model(&user).Related(&card, "CreditCard")
//// SELECT * FROM credit_cards WHERE user_id = 123; // 123 is user's primary key
// CreditCard is user's field name, it means get user's CreditCard relations and fill it into variable card
// If the field name is same as the variable's type name, like above example, it could be omitted, like:
db.Model(&user).Related(&card)
```

View File

@ -1,17 +0,0 @@
# Many To Many
```go
// User has and belongs to many languages, use `user_languages` as join table
type User struct {
gorm.Model
Languages []Language `gorm:"many2many:user_languages;"`
}
type Language struct {
gorm.Model
Name string
}
db.Model(&user).Related(&languages)
//// SELECT * FROM "languages" INNER JOIN "user_languages" ON "user_languages"."language_id" = "languages"."id" WHERE "user_languages"."user_id" = 111
```

View File

@ -1,26 +0,0 @@
# Polymorphism
Supports polymorphic has-many and has-one associations.
```go
type Cat struct {
Id int
Name string
Toy Toy `gorm:"polymorphic:Owner;"`
}
type Dog struct {
Id int
Name string
Toy Toy `gorm:"polymorphic:Owner;"`
}
type Toy struct {
Id int
Name string
OwnerId int
OwnerType string
}
```
Note: polymorphic belongs-to and many-to-many are explicitly NOT supported, and will throw errors.

View File

@ -1,7 +1,7 @@
{ {
"title": "GORM Guide", "title": "GORM Guide",
"plugins": [ "plugins": [
"prism", "-highlight", "collapsible-menu", "toc", "prism", "-highlight", "toc",
"github", "edit-link" "github", "edit-link"
], ],
"pluginsConfig": { "pluginsConfig": {
@ -22,62 +22,5 @@
"content": "<h1>Hello</h1>", "content": "<h1>Hello</h1>",
"type": "normal" "type": "normal"
} }
],
"variables": {
"chapters": {
"database/database.md": {
"name": "Databae",
"sections": [
{"name": "Database Connection", "path": "database/connect-database.md"},
{"name": "Migration", "path": "database/migration.md"}
] ]
},
"models/models.md": {
"name": "Models",
"sections": [
{"name": "Model Defination", "path": "models/defination.md"},
{"name": "Naming Conventions & Overriding", "path": "models/naming-conventions.md"},
{"name": "Associations", "path": "associations/associations.md", "sections":
[
{"name": "Belongs To", "path": "associations/belongs-to.md"},
{"name": "Has One", "path": "associations/has-one.md"},
{"name": "Has Many", "path": "associations/has-many.md"},
{"name": "Many To Many", "path": "associations/many-to-many.md"},
{"name": "Polymorphism", "path": "associations/polymorphism.md"},
{"name": "Association Mode", "path": "associations/association-mode.md"}
]
}
]
},
"curd/curd.md": {
"name": "CRUD: Reading and Writing Data",
"sections": [
{"name": "Create", "path": "curd/create.md"},
{"name": "Query", "path": "curd/query.md"},
{"name": "Preloading (Eager Loading)", "path": "curd/preloading.md"},
{"name": "Update", "path": "curd/update.md"},
{"name": "Delete / Soft Delete", "path": "curd/delete.md"}
]
},
"callbacks/callbacks.md": {
"name": "Callbacks"
},
"advanced/advanced.md": {
"name": "Advanced Usage",
"sections": [
{"name": "Error Handling", "path": "advanced/error-handling.md"},
{"name": "Transactions", "path": "advanced/transactions.md"},
{"name": "Raw SQL & SQL Builder", "path": "advanced/sql-builder.md"},
{"name": "Composite Primary Key", "path": "advanced/compose-primary-key.md"},
{"name": "Overriding Logger", "path": "advanced/logger.md"}
]
},
"development/development.md": {
"name": "Development",
"sections": [
{"name": "Write Plugins", "path": "development/plugins.md"}
]
}
}
}
} }

View File

@ -1,5 +1,7 @@
# Callbacks # Callbacks
<!-- toc -->
Callbacks are methods defined on the pointer of struct. Callbacks are methods defined on the pointer of struct.
If any callback returns an error, gorm will stop future operations and rollback all changes. If any callback returns an error, gorm will stop future operations and rollback all changes.

View File

@ -1,4 +1,86 @@
# Query # CRUD: Reading and Writing Data
<!-- toc -->
## Create
### Create Record
```go
user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
db.NewRecord(user) // => returns `true` as primary key is blank
db.Create(&user)
db.NewRecord(user) // => return `false` after `user` created
// Associations will be inserted automatically when save the record
user := User{
Name: "jinzhu",
BillingAddress: Address{Address1: "Billing Address - Address 1"},
ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
Emails: []Email{{Email: "jinzhu@example.com"}, {Email: "jinzhu-2@example@example.com"}},
Languages: []Language{{Name: "ZH"}, {Name: "EN"}},
}
db.Create(&user)
//// BEGIN TRANSACTION;
//// INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1");
//// INSERT INTO "addresses" (address1) VALUES ("Shipping Address - Address 1");
//// INSERT INTO "users" (name,billing_address_id,shipping_address_id) VALUES ("jinzhu", 1, 2);
//// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu@example.com");
//// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu-2@example.com");
//// INSERT INTO "languages" ("name") VALUES ('ZH');
//// INSERT INTO user_languages ("user_id","language_id") VALUES (111, 1);
//// INSERT INTO "languages" ("name") VALUES ('EN');
//// INSERT INTO user_languages ("user_id","language_id") VALUES (111, 2);
//// COMMIT;
```
### Create With Associations
Refer Associations for more details
### Default Values
You could defined default value in the `sql` tag, then the generated creating SQL will ignore these fields that including default value and its value is blank, and after inserted the record into databae, gorm will load those fields's value from database.
```go
type Animal struct {
ID int64
Name string `sql:"default:'galeone'"`
Age int64
}
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'
```
### Setting Primary Key In Callbacks
If you want to set primary key in `BeforeCreate` callback, you could use `scope.SetColumn`, for example:
```go
func (user *User) BeforeCreate(scope *gorm.Scope) error {
scope.SetColumn("ID", uuid.New())
return nil
}
```
### Extra Creating option
```go
// Add extra SQL option for inserting SQL
db.Set("gorm:insert_option", "ON CONFLICT").Create(&product)
// INSERT INTO products (name, code) VALUES ("name", "code") ON CONFLICT;
```
## Query
```go ```go
// Get the first record // Get the first record
@ -18,7 +100,7 @@ db.First(&user, 10)
//// SELECT * FROM users WHERE id = 10; //// SELECT * FROM users WHERE id = 10;
``` ```
## Query With Where (Plain SQL) ### Query With Where (Plain SQL)
```go ```go
// Get the first matched record // Get the first matched record
@ -46,7 +128,7 @@ db.Where("updated_at > ?", lastWeek).Find(&users)
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users) db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
``` ```
## Query With Where (Struct & Map) ### Query With Where (Struct & Map)
```go ```go
// Struct // Struct
@ -62,7 +144,7 @@ db.Where([]int64{20, 21, 22}).Find(&users)
//// SELECT * FROM users WHERE id IN (20, 21, 22); //// SELECT * FROM users WHERE id IN (20, 21, 22);
``` ```
## Query With Not ### Query With Not
```go ```go
db.Not("name", "jinzhu").First(&user) db.Not("name", "jinzhu").First(&user)
@ -88,7 +170,7 @@ db.Not(User{Name: "jinzhu"}).First(&user)
//// SELECT * FROM users WHERE name <> "jinzhu"; //// SELECT * FROM users WHERE name <> "jinzhu";
``` ```
## Query With Inline Condition ### Query With Inline Condition
```go ```go
// Get by primary key // Get by primary key
@ -111,7 +193,7 @@ db.Find(&users, map[string]interface{}{"age": 20})
//// SELECT * FROM users WHERE age = 20; //// SELECT * FROM users WHERE age = 20;
``` ```
## Query With Or ### Query With Or
```go ```go
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users) db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)
@ -125,7 +207,7 @@ db.Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2"}).Find(&users)
db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2"}).Find(&users) db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2"}).Find(&users)
``` ```
## Query Chains ### Query Chains
Gorm has a chainable API, you could use it like this Gorm has a chainable API, you could use it like this
@ -136,7 +218,7 @@ db.Where("name <> ?","jinzhu").Where("age >= ? and role <> ?",20,"admin").Find(&
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Not("name = ?", "jinzhu").Find(&users) db.Where("role = ?", "admin").Or("role = ?", "super_admin").Not("name = ?", "jinzhu").Find(&users)
``` ```
## Extra Querying option ### Extra Querying option
```go ```go
// Add extra SQL option for selecting SQL // Add extra SQL option for selecting SQL
@ -144,7 +226,7 @@ db.Set("gorm:query_option", "FOR UPDATE").First(&user, 10)
//// SELECT * FROM users WHERE id = 10 FOR UPDATE; //// SELECT * FROM users WHERE id = 10 FOR UPDATE;
``` ```
## FirstOrInit ### FirstOrInit
Get the first matched record, or initialize a record with search conditions. Get the first matched record, or initialize a record with search conditions.
@ -160,7 +242,7 @@ db.FirstOrInit(&user, map[string]interface{}{"name": "jinzhu"})
//// user -> User{Id: 111, Name: "Jinzhu", Age: 20} //// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
``` ```
### Attrs #### Attrs
Ignore some values when searching, but use them to initialize the struct if record is not found. Ignore some values when searching, but use them to initialize the struct if record is not found.
@ -180,7 +262,7 @@ db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 30}).FirstOrInit(&user)
//// user -> User{Id: 111, Name: "Jinzhu", Age: 20} //// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
``` ```
### Assign #### Assign
Ignore some values when searching, but assign it to the result regardless it is found or not. Ignore some values when searching, but assign it to the result regardless it is found or not.
@ -195,7 +277,7 @@ db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 30}).FirstOrInit(&user)
//// user -> User{Id: 111, Name: "Jinzhu", Age: 30} //// user -> User{Id: 111, Name: "Jinzhu", Age: 30}
``` ```
## FirstOrCreate ### FirstOrCreate
Get the first matched record, or create with search conditions. Get the first matched record, or create with search conditions.
@ -210,7 +292,7 @@ db.Where(User{Name: "Jinzhu"}).FirstOrCreate(&user)
//// user -> User{Id: 111, Name: "Jinzhu"} //// user -> User{Id: 111, Name: "Jinzhu"}
``` ```
### Attrs #### Attrs
Ignore some values when searching, but use them to create the struct if record is not found. like `FirstOrInit` Ignore some values when searching, but use them to create the struct if record is not found. like `FirstOrInit`
@ -227,7 +309,7 @@ db.Where(User{Name: "jinzhu"}).Attrs(User{Age: 30}).FirstOrCreate(&user)
//// user -> User{Id: 111, Name: "jinzhu", Age: 20} //// user -> User{Id: 111, Name: "jinzhu", Age: 20}
``` ```
### Assign #### Assign
Ignore some values when searching, but assign it to the record regardless it is found or not, then save back to database. like `FirstOrInit` Ignore some values when searching, but assign it to the record regardless it is found or not, then save back to database. like `FirstOrInit`
@ -245,7 +327,7 @@ db.Where(User{Name: "jinzhu"}).Assign(User{Age: 30}).FirstOrCreate(&user)
//// user -> User{Id: 111, Name: "jinzhu", Age: 30} //// user -> User{Id: 111, Name: "jinzhu", Age: 30}
``` ```
## Select ### Select
```go ```go
db.Select("name, age").Find(&users) db.Select("name, age").Find(&users)
@ -258,7 +340,7 @@ db.Table("users").Select("COALESCE(age,?)", 42).Rows()
//// SELECT COALESCE(age,'42') FROM users; //// SELECT COALESCE(age,'42') FROM users;
``` ```
## Order ### Order
```go ```go
db.Order("age desc, name").Find(&users) db.Order("age desc, name").Find(&users)
@ -274,7 +356,7 @@ db.Order("age desc").Find(&users1).Order("age", true).Find(&users2)
//// SELECT * FROM users ORDER BY age; (users2) //// SELECT * FROM users ORDER BY age; (users2)
``` ```
## Limit ### Limit
```go ```go
db.Limit(3).Find(&users) db.Limit(3).Find(&users)
@ -286,7 +368,7 @@ db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
//// SELECT * FROM users; (users2) //// SELECT * FROM users; (users2)
``` ```
## Offset ### Offset
```go ```go
db.Offset(3).Find(&users) db.Offset(3).Find(&users)
@ -298,7 +380,7 @@ db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
//// SELECT * FROM users; (users2) //// SELECT * FROM users; (users2)
``` ```
## Count ### Count
```go ```go
db.Where("name = ?", "jinzhu").Or("name = ?", "jinzhu 2").Find(&users).Count(&count) db.Where("name = ?", "jinzhu").Or("name = ?", "jinzhu 2").Find(&users).Count(&count)
@ -312,7 +394,7 @@ db.Table("deleted_users").Count(&count)
//// SELECT count(*) FROM deleted_users; //// SELECT count(*) FROM deleted_users;
``` ```
## Group & Having ### Group & Having
```go ```go
rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows() rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()
@ -332,7 +414,7 @@ type Result struct {
db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&results) db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&results)
``` ```
## Joins ### Joins
```go ```go
rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows() rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
@ -346,7 +428,7 @@ db.Table("users").Select("users.name, emails.email").Joins("left join emails on
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) 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 ### Pluck
Get selected attributes as map Get selected attributes as map
@ -363,7 +445,7 @@ db.Table("deleted_users").Pluck("name", &names)
db.Select("name, age").Find(&users) db.Select("name, age").Find(&users)
``` ```
## Scan ### Scan
Scan results into another struct. Scan results into another struct.
@ -380,7 +462,7 @@ db.Table("users").Select("name, age").Where("name = ?", 3).Scan(&result)
db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&result) db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&result)
``` ```
## Scopes ### Scopes
```go ```go
func AmountGreaterThan1000(db *gorm.DB) *gorm.DB { func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
@ -411,7 +493,7 @@ db.Scopes(OrderStatus([]string{"paid", "shipped"})).Find(&orders)
// Find all paid, shipped orders // Find all paid, shipped orders
``` ```
## Specifying The Table Name ### Specifying The Table Name
```go ```go
// Create `deleted_users` table with struct User's definition // Create `deleted_users` table with struct User's definition
@ -424,3 +506,169 @@ db.Table("deleted_users").Find(&deleted_users)
db.Table("deleted_users").Where("name = ?", "jinzhu").Delete() db.Table("deleted_users").Where("name = ?", "jinzhu").Delete()
//// DELETE FROM deleted_users WHERE name = 'jinzhu'; //// DELETE FROM deleted_users WHERE name = 'jinzhu';
``` ```
## Update
### Update All Fields
`Save` will include all fields when perform the Updating SQL, even it is not changed
```go
db.First(&user)
user.Name = "jinzhu 2"
user.Age = 100
db.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 Changed Fields
If you only want to update changed Fields, you could use `Update`, `Updates`
```go
// Update single attribute if it is changed
db.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 conditions
db.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 fields
db.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 fields
db.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 types
db.Model(&user).Updates(User{Name: "", Age: 0, Actived: false})
```
### Update Selected Fields
If you only want to update or ignore some fields when updating, you could use `Select`, `Omit`
```go
db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
//// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;
db.Model(&user).Omit("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
//// UPDATE users SET age=18, actived=false, updated_at='2013-11-17 21:34:10' WHERE id=111;
```
### Update Changed Fields Without Callbacks
Updating operations above will invoke `BeforeUpdate`, `AfterUpdate`, Update UpdatedAt timestamp, Save Associations callbacks, if you don't call them, you could use `UpdateColumn`, `UpdateColumns`
```go
// 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;
```
### Batch Updates
Callbacks won't run when do batch updates
```go
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
```
### Update with SQL Expression
```go
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;
```
### Change Updating Values In Callbacks
If you want to change updating values in callbacks using `BeforeUpdate`, `BeforeSave`, you could use `scope.SetColumn`, for example:
```go
func (user *User) BeforeSave(scope *gorm.Scope) (err error) {
if pw, err := bcrypt.GenerateFromPassword(user.Password, 0); err == nil {
scope.SetColumn("EncryptedPassword", pw)
}
}
```
### Extra Updating option
```go
// Add extra SQL option for updating SQL
db.Model(&user).Set("gorm:update_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Update("name, "hello")
//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111 OPTION (OPTIMIZE FOR UNKNOWN);
```
## Delete
```go
// Delete an existing record
db.Delete(&email)
//// DELETE from emails where id=10;
// Add extra SQL option for deleting SQL
db.Set("gorm:delete_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Delete(&email)
//// DELETE from emails where id=10 OPTION (OPTIMIZE FOR UNKNOWN);
```
### Batch Delete
```go
db.Where("email LIKE ?", "%jinzhu%").Delete(Email{})
//// DELETE from emails where email LIKE "%jinhu%";
```
### Soft Delete
If struct has `DeletedAt` field, it will get soft delete ability automatically!
Then it won't be deleted from database permanently when call `Delete`.
```go
db.Delete(&user)
//// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
// Batch Delete
db.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 them
db.Where("age = 20").Find(&user)
//// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
// Find soft deleted records with Unscoped
db.Unscoped().Where("age = 20").Find(&users)
//// SELECT * FROM users WHERE age = 20;
// Delete record permanently with Unscoped
db.Unscoped().Delete(&order)
//// DELETE FROM orders WHERE id=10;
```

View File

@ -1,76 +0,0 @@
# Create
### Create Record
```go
user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
db.NewRecord(user) // => returns `true` as primary key is blank
db.Create(&user)
db.NewRecord(user) // => return `false` after `user` created
// Associations will be inserted automatically when save the record
user := User{
Name: "jinzhu",
BillingAddress: Address{Address1: "Billing Address - Address 1"},
ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
Emails: []Email{{Email: "jinzhu@example.com"}, {Email: "jinzhu-2@example@example.com"}},
Languages: []Language{{Name: "ZH"}, {Name: "EN"}},
}
db.Create(&user)
//// BEGIN TRANSACTION;
//// INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1");
//// INSERT INTO "addresses" (address1) VALUES ("Shipping Address - Address 1");
//// INSERT INTO "users" (name,billing_address_id,shipping_address_id) VALUES ("jinzhu", 1, 2);
//// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu@example.com");
//// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu-2@example.com");
//// INSERT INTO "languages" ("name") VALUES ('ZH');
//// INSERT INTO user_languages ("user_id","language_id") VALUES (111, 1);
//// INSERT INTO "languages" ("name") VALUES ('EN');
//// INSERT INTO user_languages ("user_id","language_id") VALUES (111, 2);
//// COMMIT;
```
### Create With Associations
Refer Associations for more details
### Default Values
You could defined default value in the `sql` tag, then the generated creating SQL will ignore these fields that including default value and its value is blank, and after inserted the record into databae, gorm will load those fields's value from database.
```go
type Animal struct {
ID int64
Name string `sql:"default:'galeone'"`
Age int64
}
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'
```
### Setting Primary Key In Callbacks
If you want to set primary key in `BeforeCreate` callback, you could use `scope.SetColumn`, for example:
```go
func (user *User) BeforeCreate(scope *gorm.Scope) error {
scope.SetColumn("ID", uuid.New())
return nil
}
```
### Extra Creating option
```go
// Add extra SQL option for inserting SQL
db.Set("gorm:insert_option", "ON CONFLICT").Create(&product)
// INSERT INTO products (name, code) VALUES ("name", "code") ON CONFLICT;
```

View File

@ -1,9 +0,0 @@
# CRUD: Reading and Writing Data
{% for section in book.chapters["curd/curd.md"].sections %}
* [**{{section.name}}**](../{{section.path}})
{% if section["sections"] %}{% for subsection in section.sections %}
* [**{{ subsection.name }}**]({{ subsection.path }})
{% endfor %}{% endif %}
{% endfor %}

View File

@ -1,44 +0,0 @@
# Delete
```go
// Delete an existing record
db.Delete(&email)
//// DELETE from emails where id=10;
// Add extra SQL option for deleting SQL
db.Set("gorm:delete_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Delete(&email)
//// DELETE from emails where id=10 OPTION (OPTIMIZE FOR UNKNOWN);
```
### Batch Delete
```go
db.Where("email LIKE ?", "%jinzhu%").Delete(Email{})
//// DELETE from emails where email LIKE "%jinhu%";
```
### Soft Delete
If struct has `DeletedAt` field, it will get soft delete ability automatically!
Then it won't be deleted from database permanently when call `Delete`.
```go
db.Delete(&user)
//// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
// Batch Delete
db.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 them
db.Where("age = 20").Find(&user)
//// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
// Find soft deleted records with Unscoped
db.Unscoped().Where("age = 20").Find(&users)
//// SELECT * FROM users WHERE age = 20;
// Delete record permanently with Unscoped
db.Unscoped().Delete(&order)
//// DELETE FROM orders WHERE id=10;
```

View File

@ -1,40 +0,0 @@
# Preloading (Eager loading)
```go
db.Preload("Orders").Find(&users)
//// SELECT * FROM users;
//// SELECT * FROM orders WHERE user_id IN (1,2,3,4);
db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
//// SELECT * FROM users;
//// SELECT * FROM orders WHERE user_id IN (1,2,3,4) AND state NOT IN ('cancelled');
db.Where("state = ?", "active").Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
//// SELECT * FROM users WHERE state = 'active';
//// SELECT * FROM orders WHERE user_id IN (1,2) AND state NOT IN ('cancelled');
db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)
//// SELECT * FROM users;
//// SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many
//// SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one
//// SELECT * FROM roles WHERE id IN (4,5,6); // belongs to
```
#### Custom Preloading SQL
You could custom preloading SQL by passing in `func(db *gorm.DB) *gorm.DB` (same type as the one used for [Scopes](#scopes)), for example:
```go
db.Preload("Orders", func(db *gorm.DB) *gorm.DB {
return db.Order("orders.amount DESC")
}).Find(&users)
//// SELECT * FROM users;
//// SELECT * FROM orders WHERE user_id IN (1,2,3,4) order by orders.amount DESC;
```
#### Nested Preloading
```go
db.Preload("Orders.OrderItems").Find(&users)
db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)
```

View File

@ -1,120 +0,0 @@
# Update
### Update All Fields
`Save` will include all fields when perform the Updating SQL, even it is not changed
```go
db.First(&user)
user.Name = "jinzhu 2"
user.Age = 100
db.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 Changed Fields
If you only want to update changed Fields, you could use `Update`, `Updates`
```go
// Update single attribute if it is changed
db.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 conditions
db.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 fields
db.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 fields
db.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 types
db.Model(&user).Updates(User{Name: "", Age: 0, Actived: false})
```
### Update Selected Fields
If you only want to update or ignore some fields when updating, you could use `Select`, `Omit`
```go
db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
//// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;
db.Model(&user).Omit("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
//// UPDATE users SET age=18, actived=false, updated_at='2013-11-17 21:34:10' WHERE id=111;
```
### Update Changed Fields Without Callbacks
Updating operations above will invoke `BeforeUpdate`, `AfterUpdate`, Update UpdatedAt timestamp, Save Associations callbacks, if you don't call them, you could use `UpdateColumn`, `UpdateColumns`
```go
// 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;
```
### Batch Updates
Callbacks won't run when do batch updates
```go
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
```
### Update with SQL Expression
```go
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;
```
### Change Updating Values In Callbacks
If you want to change updating values in callbacks using `BeforeUpdate`, `BeforeSave`, you could use `scope.SetColumn`, for example:
```go
func (user *User) BeforeSave(scope *gorm.Scope) (err error) {
if pw, err := bcrypt.GenerateFromPassword(user.Password, 0); err == nil {
scope.SetColumn("EncryptedPassword", pw)
}
}
```
### Extra Updating option
```go
// Add extra SQL option for updating SQL
db.Model(&user).Set("gorm:update_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Update("name, "hello")
//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111 OPTION (OPTIMIZE FOR UNKNOWN);
```

View File

@ -1,3 +1,70 @@
# Database
<!-- toc -->
## Connecting to a database
#### MySQL
**NOTE** don't forgot params `parseTime` to handle data type `time.Time`, [more support parameters](https://github.com/go-sql-driver/mysql#parameters)
```go
import (
"github.com/jinzhu/gorm"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
}
```
#### PostgreSQL
```go
import (
"github.com/jinzhu/gorm"
_ "github.com/lib/pq"
)
func main() {
db, err := gorm.Open("postgres", "user=gorm dbname=gorm sslmode=disable")
}
```
#### Sqlite3
```go
import (
"github.com/jinzhu/gorm"
_ "github.com/mattn/go-sqlite3"
)
func main() {
db, err := gorm.Open("sqlite3", "/tmp/gorm.db")
}
```
#### Write Dialect for unsupported databases
GORM officially support above databases, for unsupported databaes, you could write a dialect for that.
Refer: https://github.com/jinzhu/gorm/blob/master/dialect.go
## Generic database object *sql.DB
[*sql.DB](http://golang.org/pkg/database/sql/#DB)
```go
// Get generic database object *sql.DB to use its functions
db.DB()
// Connection Pool
db.DB().SetMaxIdleConns(10)
db.DB().SetMaxOpenConns(100)
// Ping
db.DB().Ping()
```
## Migration ## Migration
<!-- toc --> <!-- toc -->

View File

@ -1,66 +0,0 @@
# Database Connection
<!-- toc -->
## Connecting to a database
#### MySQL
**NOTE** don't forgot params `parseTime` to handle data type `time.Time`, [more support parameters](https://github.com/go-sql-driver/mysql#parameters)
```go
import (
"github.com/jinzhu/gorm"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
}
```
#### PostgreSQL
```go
import (
"github.com/jinzhu/gorm"
_ "github.com/lib/pq"
)
func main() {
db, err := gorm.Open("postgres", "user=gorm dbname=gorm sslmode=disable")
}
```
#### Sqlite3
```go
import (
"github.com/jinzhu/gorm"
_ "github.com/mattn/go-sqlite3"
)
func main() {
db, err := gorm.Open("sqlite3", "/tmp/gorm.db")
}
```
#### Write Dialect for unsupported databases
GORM officially support above databases, for unsupported databaes, you could write a dialect for that.
Refer: https://github.com/jinzhu/gorm/blob/master/dialect.go
## Generic database object *sql.DB
[*sql.DB](http://golang.org/pkg/database/sql/#DB)
```go
// Get generic database object *sql.DB to use its functions
db.DB()
// Connection Pool
db.DB().SetMaxIdleConns(10)
db.DB().SetMaxOpenConns(100)
// Ping
db.DB().Ping()
```

View File

@ -1,5 +0,0 @@
# Database
{% for section in book.chapters["database/database.md"].sections %}
* [**{{section.name}}**](../{{section.path}})
{% endfor %}

View File

@ -1,5 +1,7 @@
# Gorm Development # Gorm Development
<!-- toc -->
## Architecture ## Architecture
The most notable component of Gorm is`gorm.DB`, which hold database connection. It could be initialized like this: The most notable component of Gorm is`gorm.DB`, which hold database connection. It could be initialized like this:

View File

@ -1,8 +0,0 @@
# Models
{% for section in book.chapters["models/models.md"].sections %}
* [**{{section.name}}**](../{{section.path}})
{% if section["sections"] %}{% for subsection in section.sections %}
* [**{{ subsection.name }}**]({{ subsection.path }})
{% endfor %}{% endif %}
{% endfor %}