gorm/README.md

1162 lines
32 KiB
Markdown
Raw Normal View History

2013-10-25 12:24:29 +04:00
# GORM
2014-01-03 10:54:47 +04:00
The fantastic ORM library for Golang, aims to be developer friendly.
2013-10-25 12:24:29 +04:00
[![wercker status](https://app.wercker.com/status/0cb7bb1039e21b74f8274941428e0921/s/master "wercker status")](https://app.wercker.com/project/bykey/0cb7bb1039e21b74f8274941428e0921)
2013-10-28 06:09:44 +04:00
## Overview
2015-02-24 17:06:42 +03:00
* Full-Featured ORM (almost)
2013-10-28 06:09:44 +04:00
* Chainable API
* Auto Migrations
2015-02-24 17:06:42 +03:00
* Relations (Has One, Has Many, Belongs To, Many To Many, [Polymorphism](#polymorphism))
* Callbacks (Before/After Create/Save/Update/Delete/Find)
2015-02-11 14:27:58 +03:00
* Preloading (eager loading)
* Transactions
2015-02-24 17:06:42 +03:00
* Embed Anonymous Struct
* Soft Deletes
2014-07-18 06:16:08 +04:00
* Customizable Logger
2013-11-17 09:22:09 +04:00
* Iteration Support via [Rows](#row--rows)
2013-11-07 08:12:25 +04:00
* Every feature comes with tests
* Developer Friendly
2013-10-28 06:09:44 +04:00
2014-07-18 06:16:08 +04:00
# Getting Started
2014-07-18 06:16:08 +04:00
## Install
2014-07-18 06:16:08 +04:00
```
go get -u github.com/jinzhu/gorm
```
2014-07-18 06:16:08 +04:00
## Define Models (Structs)
2013-11-17 08:02:22 +04:00
2013-10-27 17:37:31 +04:00
```go
2013-11-15 13:27:16 +04:00
type User struct {
2015-02-24 17:06:42 +03:00
ID int
2014-09-16 04:59:04 +04:00
Birthday time.Time
2015-02-24 17:06:42 +03:00
Age int
2015-03-09 12:22:16 +03:00
Name string `sql:"size:255"` // Default size for string is 255, you could reset it with this tag
2015-03-11 12:05:58 +03:00
Num int `sql:"AUTO_INCREMENT"`
2014-09-16 04:59:04 +04:00
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt time.Time
Emails []Email // One-To-Many relationship (has many)
BillingAddress Address // One-To-One relationship (has one)
2015-02-24 17:06:42 +03:00
BillingAddressID sql.NullInt64 // Foreign key of BillingAddress
2014-09-16 04:59:04 +04:00
ShippingAddress Address // One-To-One relationship (has one)
2015-02-24 17:06:42 +03:00
ShippingAddressID int // Foreign key of ShippingAddress
IgnoreMe int `sql:"-"` // Ignore this field
2014-09-16 04:59:04 +04:00
Languages []Language `gorm:"many2many:user_languages;"` // Many-To-Many relationship, 'user_languages' is join table
2013-10-27 17:37:31 +04:00
}
2013-11-17 08:02:22 +04:00
type Email struct {
2015-03-09 12:22:16 +03:00
ID int
UserID int `sql:"index"` // Foreign key (belongs to), tag `index` will create index for this field when using AutoMigrate
Email string `sql:"type:varchar(100);unique_index"` // Set field's sql type, tag `unique_index` will create unique index
2014-09-16 04:59:04 +04:00
Subscribed bool
2013-11-02 17:02:54 +04:00
}
2013-10-28 06:09:44 +04:00
2013-11-17 08:02:22 +04:00
type Address struct {
2015-02-24 17:06:42 +03:00
ID int
2014-09-16 04:59:04 +04:00
Address1 string `sql:"not null;unique"` // Set field as not nullable and unique
Address2 string `sql:"type:varchar(100);unique"`
Post sql.NullString `sql:"not null"`
2013-11-02 17:02:54 +04:00
}
2014-07-30 18:50:27 +04:00
type Language struct {
2015-02-24 17:06:42 +03:00
ID int
2015-03-09 12:22:16 +03:00
Name string `sql:"index:idx_name_code"` // Create index with name, and will create combined index if find other fields defined same name
Code string `sql:"index:idx_name_code"` // `unique_index` also works
2014-07-30 18:50:27 +04:00
}
2013-11-02 17:02:54 +04:00
```
2015-02-24 17:06:42 +03:00
## Conventions
* Table name is the plural of struct name's snake case, you can disable pluralization with `db.SingularTable(true)`, or [Specifying The Table Name For A Struct Permanently With TableName](#specifying-the-table-name-for-a-struct-permanently-with-tablename)
```go
2015-03-09 12:22:16 +03:00
type User struct{} // struct User's database table name is "users" by default, will be "user" if you disabled pluralisation
2015-02-24 17:06:42 +03:00
```
* Column name is the snake case of field's name
* Use `ID` field as primary key
* Use `CreatedAt` to store record's created time if field exists
* Use `UpdatedAt` to store record's updated time if field exists
* Use `DeletedAt` to store record's deleted time if field exists [Soft Delete](#soft-delete)
2014-07-18 06:16:08 +04:00
## Initialize Database
2013-11-03 07:32:25 +04:00
```go
2014-07-18 06:16:08 +04:00
import (
2014-09-16 04:59:04 +04:00
"github.com/jinzhu/gorm"
_ "github.com/lib/pq"
_ "github.com/go-sql-driver/mysql"
_ "github.com/mattn/go-sqlite3"
2014-07-18 06:16:08 +04:00
)
2013-11-03 07:38:53 +04:00
2014-03-15 05:05:08 +04:00
db, err := gorm.Open("postgres", "user=gorm dbname=gorm sslmode=disable")
2015-03-09 12:22:16 +03:00
// db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
2014-07-18 06:16:08 +04:00
// db, err := gorm.Open("sqlite3", "/tmp/gorm.db")
2013-11-04 16:32:46 +04:00
// You can also use an existing database connection handle
// dbSql, _ := sql.Open("postgres", "user=gorm dbname=gorm sslmode=disable")
// db := gorm.Open("postgres", dbSql)
// Get database connection handle [*sql.DB](http://golang.org/pkg/database/sql/#DB)
2014-07-18 06:16:08 +04:00
db.DB()
2013-11-03 07:38:53 +04:00
2014-07-18 06:16:08 +04:00
// Then you could invoke `*sql.DB`'s functions with it
db.DB().Ping()
db.DB().SetMaxIdleConns(10)
db.DB().SetMaxOpenConns(100)
2014-07-18 06:16:08 +04:00
// Disable table name's pluralization
2013-11-06 17:43:41 +04:00
db.SingularTable(true)
```
2013-11-03 07:32:25 +04:00
2014-07-18 06:16:08 +04:00
## Migration
2013-11-02 17:02:54 +04:00
```go
2014-07-18 06:16:08 +04:00
// Create table
2014-09-12 12:40:55 +04:00
db.CreateTable(&User{})
2013-11-02 17:02:54 +04:00
// Drop table
2014-09-12 12:40:55 +04:00
db.DropTable(&User{})
2013-11-07 07:42:36 +04:00
2014-07-18 06:16:08 +04:00
// Automating Migration
2014-09-12 12:40:55 +04:00
db.AutoMigrate(&User{})
db.AutoMigrate(&User{}, &Product{}, &Order{})
2014-07-18 06:16:08 +04:00
// Feel free to change your struct, AutoMigrate will keep your database up-to-date.
2015-03-09 12:22:16 +03:00
// AutoMigrate will ONLY add *new columns* and *new indexes*,
// WON'T update current column's type or delete unused columns, to protect your data.
2014-07-18 06:16:08 +04:00
// If the table is not existing, AutoMigrate will create the table automatically.
2013-11-02 17:02:54 +04:00
```
2013-10-27 17:37:31 +04:00
2014-07-18 06:16:08 +04:00
# Basic CRUD
2013-11-23 17:38:31 +04:00
2014-07-18 06:16:08 +04:00
## Create Record
2013-11-23 17:38:31 +04:00
```go
2014-07-18 06:16:08 +04:00
user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
2015-03-09 12:22:16 +03:00
db.NewRecord(user) // => returns `true` if primary key is blank
2013-11-23 17:38:31 +04:00
2014-07-18 06:16:08 +04:00
db.Create(&user)
2013-11-23 17:38:31 +04:00
2015-03-09 12:22:16 +03:00
db.NewRecord(user) // => return `false` after `user` created
2013-11-03 06:31:36 +04:00
2015-03-09 12:22:16 +03:00
// Associations will be inserted automatically when save the record
2013-11-03 06:31:36 +04:00
user := User{
2014-09-16 04:59:04 +04:00
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"}},
2013-11-03 06:31:36 +04:00
}
2014-07-18 06:16:08 +04:00
db.Create(&user)
//// BEGIN TRANSACTION;
2013-11-03 06:31:36 +04:00
//// 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");
2014-07-30 18:50:27 +04:00
//// 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;
2013-11-03 06:31:36 +04:00
```
2015-03-09 12:22:16 +03:00
Refer [Associations](#associations) for more details
2014-07-18 06:16:08 +04:00
2013-11-02 17:02:54 +04:00
## Query
```go
// Get the first record
db.First(&user)
//// SELECT * FROM users ORDER BY id LIMIT 1;
2013-10-27 17:37:31 +04:00
// Get the last record
db.Last(&user)
//// SELECT * FROM users ORDER BY id DESC LIMIT 1;
// Get all records
2013-11-02 17:02:54 +04:00
db.Find(&users)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users;
2013-11-02 17:02:54 +04:00
2013-11-15 13:27:16 +04:00
// Get record with primary key
2013-11-02 17:02:54 +04:00
db.First(&user, 10)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users WHERE id = 10;
2013-11-02 17:02:54 +04:00
```
2014-07-18 06:16:08 +04:00
### Query With Where (Plain SQL)
2013-11-02 17:02:54 +04:00
```go
// Get the first matched record
2013-10-27 17:37:31 +04:00
db.Where("name = ?", "jinzhu").First(&user)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE name = 'jinzhu' limit 1;
2013-10-27 17:37:31 +04:00
2013-11-02 17:02:54 +04:00
// Get all matched records
2013-10-27 17:37:31 +04:00
db.Where("name = ?", "jinzhu").Find(&users)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE name = 'jinzhu';
2013-10-27 17:37:31 +04:00
db.Where("name <> ?", "jinzhu").Find(&users)
2013-11-02 17:02:54 +04:00
// IN
2013-11-03 17:19:38 +04:00
db.Where("name in (?)", []string{"jinzhu", "jinzhu 2"}).Find(&users)
2013-11-02 17:02:54 +04:00
// LIKE
2013-10-28 05:05:44 +04:00
db.Where("name LIKE ?", "%jin%").Find(&users)
2013-11-02 17:02:54 +04:00
2014-07-18 06:16:08 +04:00
// AND
2013-11-02 17:02:54 +04:00
db.Where("name = ? and age >= ?", "jinzhu", "22").Find(&users)
```
2013-11-03 06:09:56 +04:00
### Query With Where (Struct & Map)
2013-11-02 17:02:54 +04:00
```go
2014-07-18 06:16:08 +04:00
// Struct
2013-10-29 13:37:45 +04:00
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 LIMIT 1;
2014-07-18 06:16:08 +04:00
// Map
2013-11-02 17:02:54 +04:00
db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
//// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;
2013-11-03 06:09:56 +04:00
2014-07-18 06:16:08 +04:00
// Slice of primary keys
2013-11-03 06:09:56 +04:00
db.Where([]int64{20, 21, 22}).Find(&users)
//// SELECT * FROM users WHERE id IN (20, 21, 22);
2013-11-02 17:02:54 +04:00
```
2013-11-03 06:09:56 +04:00
### Query With Not
2013-11-02 17:02:54 +04:00
```go
db.Not("name", "jinzhu").First(&user)
//// SELECT * FROM users WHERE name <> "jinzhu" LIMIT 1;
2013-10-27 17:37:31 +04:00
2013-11-02 17:02:54 +04:00
// Not In
db.Not("name", []string{"jinzhu", "jinzhu 2"}).Find(&users)
//// SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");
2014-07-18 06:16:08 +04:00
// Not In slice of primary keys
2013-10-31 14:12:18 +04:00
db.Not([]int64{1,2,3}).First(&user)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE id NOT IN (1,2,3);
2013-10-31 14:12:18 +04:00
db.Not([]int64{}).First(&user)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users;
2014-07-18 06:16:08 +04:00
// Plain SQL
2013-10-31 18:49:48 +04:00
db.Not("name = ?", "jinzhu").First(&user)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE NOT(name = "jinzhu");
2014-07-18 06:16:08 +04:00
// Struct
2013-10-31 14:12:18 +04:00
db.Not(User{Name: "jinzhu"}).First(&user)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE name <> "jinzhu";
```
2013-11-03 06:49:09 +04:00
### Query With Inline Condition
2013-10-31 14:12:18 +04:00
2013-11-02 17:02:54 +04:00
```go
2014-07-18 06:16:08 +04:00
// Get by primary key
2013-10-27 18:36:43 +04:00
db.First(&user, 23)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE id = 23 LIMIT 1;
2014-07-18 06:16:08 +04:00
// Plain SQL
2013-11-02 17:02:54 +04:00
db.Find(&user, "name = ?", "jinzhu")
//// SELECT * FROM users WHERE name = "jinzhu";
2014-07-18 06:16:08 +04:00
db.Find(&users, "name <> ? AND age > ?", "jinzhu", 20)
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE name <> "jinzhu" AND age > 20;
2014-07-18 06:16:08 +04:00
// Struct
2013-11-02 17:02:54 +04:00
db.Find(&users, User{Age: 20})
//// SELECT * FROM users WHERE age = 20;
2014-07-18 06:16:08 +04:00
// Map
2013-10-29 13:52:37 +04:00
db.Find(&users, map[string]interface{}{"age": 20})
2013-11-02 17:02:54 +04:00
//// SELECT * FROM users WHERE age = 20;
```
2013-11-03 06:09:56 +04:00
### Query With Or
2013-11-03 06:49:09 +04:00
```go
2013-11-03 06:09:56 +04:00
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)
//// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';
2014-07-18 06:16:08 +04:00
// Struct
2013-11-03 06:09:56 +04:00
db.Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2"}).Find(&users)
//// SELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';
2014-07-18 06:16:08 +04:00
// Map
2013-11-03 06:09:56 +04:00
db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2"}).Find(&users)
```
### Query Chains
2014-07-18 06:16:08 +04:00
Gorm has a chainable API, you could use it like this
2013-11-03 06:09:56 +04:00
```go
2013-11-03 06:49:09 +04:00
db.Where("name <> ?","jinzhu").Where("age >= ? and role <> ?",20,"admin").Find(&users)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users WHERE name <> 'jinzhu' AND age >= 20 AND role <> 'admin';
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Not("name = ?", "jinzhu").Find(&users)
```
2015-02-11 14:27:58 +03:00
### 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
```
2013-11-03 06:09:56 +04:00
## Update
```go
2014-07-18 06:16:08 +04:00
// Update an existing struct
db.First(&user)
2013-11-03 06:09:56 +04:00
user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)
2013-11-17 17:39:50 +04:00
//// UPDATE users SET name='jinzhu 2', age=100, updated_at = '2013-11-17 21:34:10' WHERE id=111;
2013-11-03 06:09:56 +04:00
2015-02-24 12:11:35 +03:00
db.Where("active = ?", true).Save(&user)
//// UPDATE users SET name='jinzhu 2', age=100, updated_at = '2013-11-17 21:34:10' WHERE id=111 AND active = true;
2014-07-18 06:16:08 +04:00
// Update an attribute if it is changed
2013-11-03 06:09:56 +04:00
db.Model(&user).Update("name", "hello")
2013-11-17 17:39:50 +04:00
//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111;
2013-11-03 06:09:56 +04:00
2015-02-24 12:11:35 +03:00
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;
2013-11-03 06:09:56 +04:00
db.First(&user, 111).Update("name", "hello")
//// SELECT * FROM users LIMIT 1;
2013-11-17 17:39:50 +04:00
//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111;
2013-11-03 06:09:56 +04:00
2014-07-18 06:16:08 +04:00
// Update multiple attributes if they are changed
2015-03-11 06:15:23 +03:00
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
// Update multiple attributes if they are changed (update with struct only works with none zero values)
2013-11-03 06:09:56 +04:00
db.Model(&user).Updates(User{Name: "hello", Age: 18})
2013-11-17 17:39:50 +04:00
//// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;
2013-11-03 06:09:56 +04:00
```
2014-07-18 06:16:08 +04:00
### Update Without Callbacks
By default, update will call BeforeUpdate, AfterUpdate callbacks, if you want to update w/o callbacks and w/o saving associations:
2013-11-17 17:39:50 +04:00
```go
db.Model(&user).UpdateColumn("name", "hello")
//// UPDATE users SET name='hello' WHERE id = 111;
2015-03-11 06:15:23 +03:00
// Update with struct only works with none zero values, or use map[string]interface{}
2013-11-17 17:39:50 +04:00
db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18})
//// UPDATE users SET name='hello', age=18 WHERE id = 111;
```
2014-07-18 06:16:08 +04:00
### Batch Updates
2014-06-05 14:23:22 +04:00
```go
2014-07-18 06:16:08 +04:00
db.Table("users").Where("id = ?", 10).Updates(map[string]interface{}{"name": "hello", "age": 18})
//// UPDATE users SET name='hello', age=18 WHERE id = 10;
2015-03-11 06:15:23 +03:00
// Update with struct only works with none zero values, or use map[string]interface{}
2014-07-18 06:16:08 +04:00
db.Model(User{}).Updates(User{Name: "hello", Age: 18})
//// UPDATE users SET name='hello', age=18;
2015-03-11 06:15:23 +03:00
// Callbacks won't run when do batch updates
2014-07-18 06:16:08 +04:00
2015-03-11 06:15:23 +03:00
// Use `RowsAffected` to get the count of affected records
2014-06-05 14:23:22 +04:00
db.Model(User{}).Updates(User{Name: "hello", Age: 18}).RowsAffected
```
2013-11-03 06:09:56 +04:00
2015-02-24 17:06:42 +03:00
### Update with SQL Expression
```go
DB.Model(&product).Update("price", gorm.Expr("price * ? + ?", 2, 100))
//// UPDATE "products" SET "code" = 'L1212', "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 "code" = 'L1212', "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;
```
2014-07-18 06:16:08 +04:00
## Delete
2013-11-03 06:09:56 +04:00
```go
2014-07-18 06:16:08 +04:00
// Delete an existing record
2013-11-03 06:09:56 +04:00
db.Delete(&email)
//// DELETE from emails where id=10;
2013-11-03 06:09:56 +04:00
```
2014-07-18 06:16:08 +04:00
### Batch Delete
2013-11-03 06:09:56 +04:00
```go
db.Where("email LIKE ?", "%jinzhu%").Delete(Email{})
//// DELETE from emails where email LIKE "%jinhu%";
2013-11-03 06:09:56 +04:00
```
### Soft Delete
2014-07-18 06:16:08 +04:00
If struct has `DeletedAt` field, it will get soft delete ability automatically!
Then it won't be deleted from database permanently when call `Delete`.
2013-11-03 06:09:56 +04:00
```go
db.Delete(&user)
//// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
2014-07-18 06:16:08 +04:00
// Batch Delete
2013-11-03 06:09:56 +04:00
db.Where("age = ?", 20).Delete(&User{})
//// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
2014-07-18 06:16:08 +04:00
// Soft deleted records will be ignored when query them
2013-11-03 06:09:56 +04:00
db.Where("age = 20").Find(&user)
2015-01-22 20:43:47 +03:00
//// SELECT * FROM users WHERE age = 20 AND (deleted_at IS NULL OR deleted_at <= '0001-01-02');
2013-11-03 06:09:56 +04:00
2013-11-15 13:27:16 +04:00
// Find soft deleted records with Unscoped
2013-11-03 06:09:56 +04:00
db.Unscoped().Where("age = 20").Find(&users)
//// SELECT * FROM users WHERE age = 20;
2013-11-15 13:27:16 +04:00
// Delete record permanently with Unscoped
2013-11-03 06:09:56 +04:00
db.Unscoped().Delete(&order)
//// DELETE FROM orders WHERE id=10;
2013-11-03 06:09:56 +04:00
```
2014-07-30 18:50:27 +04:00
## Associations
### Has One
```go
// User has one address
db.Model(&user).Related(&address)
//// SELECT * FROM addresses WHERE id = 123; // 123 is user's foreign key AddressId
// Specify the foreign key
db.Model(&user).Related(&address1, "BillingAddressId")
//// SELECT * FROM addresses WHERE id = 123; // 123 is user's foreign key BillingAddressId
```
### Belongs To
```go
// Email belongs to user
db.Model(&email).Related(&user)
//// SELECT * FROM users WHERE id = 111; // 111 is email's foreign key UserId
// Specify the foreign key
db.Model(&email).Related(&user, "ProfileId")
//// SELECT * FROM users WHERE id = 111; // 111 is email's foreign key ProfileId
```
### Has Many
```go
// User has many emails
db.Model(&user).Related(&emails)
//// SELECT * FROM emails WHERE user_id = 111;
// user_id is the foreign key, 111 is user's primary key's value
// Specify the foreign key
db.Model(&user).Related(&emails, "ProfileId")
//// SELECT * FROM emails WHERE profile_id = 111;
// profile_id is the foreign key, 111 is user's primary key's value
```
### Many To Many
```go
// User has many languages and belongs to many languages
db.Model(&user).Related(&languages, "Languages")
//// SELECT * FROM "languages" INNER JOIN "user_languages" ON "user_languages"."language_id" = "languages"."id" WHERE "user_languages"."user_id" = 111
// `Languages` is user's column name, this column's tag defined join table like this `gorm:"many2many:user_languages;"`
```
There is also a mode used to handle many to many relations easily
```go
// Query
db.Model(&user).Association("Languages").Find(&languages)
// same as `db.Model(&user).Related(&languages, "Languages")`
db.Where("name = ?", "ZH").First(&languageZH)
db.Where("name = ?", "EN").First(&languageEN)
// Append
db.Model(&user).Association("Languages").Append([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Append([]Language{{Name: "DE"}})
db.Model(&user).Association("Languages").Append(Language{Name: "DE"})
// Delete
db.Model(&user).Association("Languages").Delete([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Delete(languageZH, languageEN)
// Replace
db.Model(&user).Association("Languages").Replace([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Replace(Language{Name: "DE"}, languageEN)
// Count
db.Model(&user).Association("Languages").Count()
// Return the count of languages the user has
// Clear
db.Model(&user).Association("Languages").Clear()
// Remove all relations between the user and languages
```
### 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.
2014-07-18 06:16:08 +04:00
## Advanced Usage
2013-11-02 17:02:54 +04:00
2014-07-18 06:16:08 +04:00
## FirstOrInit
2013-11-03 06:49:09 +04:00
2014-07-18 06:16:08 +04:00
Get the first matched record, or initialize a record with search conditions.
2013-11-02 17:02:54 +04:00
```go
2014-07-18 06:16:08 +04:00
// Unfound
2013-11-02 17:02:54 +04:00
db.FirstOrInit(&user, User{Name: "non_existing"})
2014-07-18 06:16:08 +04:00
//// user -> User{Name: "non_existing"}
2013-10-27 18:18:06 +04:00
2014-07-18 06:16:08 +04:00
// Found
2013-10-29 16:32:27 +04:00
db.Where(User{Name: "Jinzhu"}).FirstOrInit(&user)
2014-07-18 06:16:08 +04:00
//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
2013-11-02 17:02:54 +04:00
db.FirstOrInit(&user, map[string]interface{}{"name": "jinzhu"})
2014-07-18 06:16:08 +04:00
//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
2013-11-02 17:02:54 +04:00
```
2014-07-18 06:16:08 +04:00
### Attrs
2013-11-02 17:02:54 +04:00
2014-07-18 06:16:08 +04:00
Ignore some values when searching, but use them to initialize the struct if record is not found.
2013-11-02 17:02:54 +04:00
```go
2014-07-18 06:16:08 +04:00
// Unfound
2013-11-02 17:02:54 +04:00
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrInit(&user)
//// SELECT * FROM USERS WHERE name = 'non_existing';
2014-07-18 06:16:08 +04:00
//// user -> User{Name: "non_existing", Age: 20}
2013-11-02 17:02:54 +04:00
db.Where(User{Name: "noexisting_user"}).Attrs("age", 20).FirstOrInit(&user)
2014-07-18 06:16:08 +04:00
//// SELECT * FROM USERS WHERE name = 'non_existing';
//// user -> User{Name: "non_existing", Age: 20}
2013-11-02 17:02:54 +04:00
2014-07-18 06:16:08 +04:00
// Found
2013-11-02 17:02:54 +04:00
db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 30}).FirstOrInit(&user)
//// SELECT * FROM USERS WHERE name = jinzhu';
2014-07-18 06:16:08 +04:00
//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
2013-11-03 06:18:16 +04:00
```
2013-10-30 11:33:34 +04:00
2014-07-18 06:16:08 +04:00
### Assign
2013-11-02 17:02:54 +04:00
2014-07-18 06:16:08 +04:00
Ignore some values when searching, but assign it to the result regardless it is found or not.
2013-11-02 17:02:54 +04:00
```go
2014-07-18 06:16:08 +04:00
// Unfound
2013-11-02 17:02:54 +04:00
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrInit(&user)
2014-07-18 06:16:08 +04:00
//// user -> User{Name: "non_existing", Age: 20}
2013-11-02 17:02:54 +04:00
2014-07-18 06:16:08 +04:00
// Found
2013-11-02 17:02:54 +04:00
db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 30}).FirstOrInit(&user)
2014-07-18 06:16:08 +04:00
//// SELECT * FROM USERS WHERE name = jinzhu';
//// user -> User{Id: 111, Name: "Jinzhu", Age: 30}
2013-11-02 17:02:54 +04:00
```
## FirstOrCreate
2014-07-18 06:16:08 +04:00
Get the first matched record, or create with search conditions.
2013-11-02 17:02:54 +04:00
```go
2014-07-18 06:16:08 +04:00
// Unfound
2013-11-02 17:02:54 +04:00
db.FirstOrCreate(&user, User{Name: "non_existing"})
2014-07-18 06:16:08 +04:00
//// INSERT INTO "users" (name) VALUES ("non_existing");
//// user -> User{Id: 112, Name: "non_existing"}
2013-11-02 17:02:54 +04:00
2014-07-18 06:16:08 +04:00
// Found
2013-10-29 16:32:27 +04:00
db.Where(User{Name: "Jinzhu"}).FirstOrCreate(&user)
2014-07-18 06:16:08 +04:00
//// user -> User{Id: 111, Name: "Jinzhu"}
2013-11-02 17:02:54 +04:00
```
2014-07-18 06:16:08 +04:00
### Attrs
2013-10-29 16:32:27 +04:00
2014-07-18 06:16:08 +04:00
Ignore some values when searching, but use them to create the struct if record is not found. like `FirstOrInit`
2013-11-02 17:02:54 +04:00
```go
2014-07-18 06:16:08 +04:00
// Unfound
2013-11-02 17:02:54 +04:00
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
//// SELECT * FROM users WHERE name = 'non_existing';
2014-07-18 06:16:08 +04:00
//// INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
//// user -> User{Id: 112, Name: "non_existing", Age: 20}
2013-10-31 05:34:27 +04:00
2014-07-18 06:16:08 +04:00
// Found
2013-11-03 06:09:56 +04:00
db.Where(User{Name: "jinzhu"}).Attrs(User{Age: 30}).FirstOrCreate(&user)
2014-07-18 06:16:08 +04:00
//// SELECT * FROM users WHERE name = 'jinzhu';
//// user -> User{Id: 111, Name: "jinzhu", Age: 20}
2013-11-02 17:02:54 +04:00
```
2014-07-18 06:16:08 +04:00
### Assign
2013-10-31 05:34:27 +04:00
2014-07-18 06:16:08 +04:00
Ignore some values when searching, but assign it to the record regardless it is found or not, then save back to database. like `FirstOrInit`
2013-10-31 05:34:27 +04:00
2013-11-02 17:02:54 +04:00
```go
2014-07-18 06:16:08 +04:00
// Unfound
2013-11-02 17:02:54 +04:00
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrCreate(&user)
2014-07-18 06:16:08 +04:00
//// SELECT * FROM users WHERE name = 'non_existing';
//// INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
2013-11-02 17:02:54 +04:00
//// user -> User{Id: 112, Name: "non_existing", Age: 20}
2014-07-18 06:16:08 +04:00
// Found
2013-11-03 06:09:56 +04:00
db.Where(User{Name: "jinzhu"}).Assign(User{Age: 30}).FirstOrCreate(&user)
//// SELECT * FROM users WHERE name = 'jinzhu';
2013-11-02 17:02:54 +04:00
//// UPDATE users SET age=30 WHERE id = 111;
2014-07-18 06:16:08 +04:00
//// user -> User{Id: 111, Name: "jinzhu", Age: 30}
2013-11-02 17:02:54 +04:00
```
2013-11-03 06:09:56 +04:00
## Select
2013-11-02 17:02:54 +04:00
```go
2013-11-03 06:09:56 +04:00
db.Select("name, age").Find(&users)
//// SELECT name, age FROM users;
db.Select([]string{"name", "age"}).Find(&users)
//// SELECT name, age FROM users;
db.Table("users").Select("COALESCE(age,?)", 42).Rows()
//// SELECT COALESCE(age,'42') FROM users;
2013-11-03 06:09:56 +04:00
```
2013-10-30 11:33:34 +04:00
2013-11-03 06:09:56 +04:00
## Order
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
```go
2013-10-27 17:37:31 +04:00
db.Order("age desc, name").Find(&users)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users ORDER BY age desc, name;
2013-11-15 13:27:16 +04:00
// Multiple orders
2013-10-27 18:18:06 +04:00
db.Order("age desc").Order("name").Find(&users)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users ORDER BY age desc, name;
2013-10-28 05:18:34 +04:00
// ReOrder
db.Order("age desc").Find(&users1).Order("age", true).Find(&users2)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users ORDER BY age desc; (users1)
//// SELECT * FROM users ORDER BY age; (users2)
```
2013-10-28 05:18:34 +04:00
2013-11-03 06:09:56 +04:00
## Limit
```go
2013-10-27 17:37:31 +04:00
db.Limit(3).Find(&users)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users LIMIT 3;
2013-10-27 17:37:31 +04:00
2014-07-18 06:16:08 +04:00
// Cancel limit condition with -1
2013-11-03 06:09:56 +04:00
db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
//// SELECT * FROM users LIMIT 10; (users1)
//// SELECT * FROM users; (users2)
```
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
## Offset
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
```go
db.Offset(3).Find(&users)
//// SELECT * FROM users OFFSET 3;
2013-10-27 17:37:31 +04:00
2014-07-18 06:16:08 +04:00
// Cancel offset condition with -1
2013-11-03 06:09:56 +04:00
db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
//// SELECT * FROM users OFFSET 10; (users1)
//// SELECT * FROM users; (users2)
```
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
## Count
2013-10-27 18:18:06 +04:00
2013-11-03 06:09:56 +04:00
```go
db.Where("name = ?", "jinzhu").Or("name = ?", "jinzhu 2").Find(&users).Count(&count)
//// SELECT * from USERS WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (users)
//// SELECT count(*) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (count)
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
db.Model(User{}).Where("name = ?", "jinzhu").Count(&count)
2014-07-18 06:16:08 +04:00
//// SELECT count(*) FROM users WHERE name = 'jinzhu'; (count)
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
db.Table("deleted_users").Count(&count)
//// SELECT count(*) FROM deleted_users;
```
## Pluck
2013-10-27 18:18:06 +04:00
2014-07-18 06:16:08 +04:00
Get selected attributes as map
2013-11-03 06:09:56 +04:00
```go
2013-10-27 17:37:31 +04:00
var ages []int64
2013-10-28 05:05:44 +04:00
db.Find(&users).Pluck("age", &ages)
2013-11-03 06:09:56 +04:00
2013-10-27 18:18:06 +04:00
var names []string
db.Model(&User{}).Pluck("name", &names)
2013-10-27 17:37:31 +04:00
2013-11-03 06:09:56 +04:00
db.Table("deleted_users").Pluck("name", &names)
2013-11-11 17:55:44 +04:00
2014-07-18 06:16:08 +04:00
// Requesting more than one column? Do it like this:
2013-11-11 17:55:44 +04:00
db.Select("name, age").Find(&users)
2013-11-03 06:09:56 +04:00
```
2014-07-18 06:16:08 +04:00
## 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
2014-10-28 12:01:05 +03:00
It is even possible to get query result as `*sql.Row` or `*sql.Rows`
2014-07-18 06:16:08 +04:00
```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() {
2014-09-16 04:59:04 +04:00
...
rows.Scan(&name, &age, &email)
...
2014-07-18 06:16:08 +04:00
}
// 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() {
2014-09-16 04:59:04 +04:00
...
rows.Scan(&name, &age, &email)
...
2014-07-18 06:16:08 +04:00
}
```
## Scan
Scan results into another struct.
```go
type Result struct {
Name string
Age int
}
var result Result
db.Table("users").Select("name, age").Where("name = ?", 3).Scan(&result)
// Raw SQL
db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&result)
```
## Group & Having
```go
rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()
for rows.Next() {
2014-09-16 04:59:04 +04:00
...
2014-07-18 06:16:08 +04:00
}
rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Rows()
for rows.Next() {
2014-09-16 04:59:04 +04:00
...
2014-07-18 06:16:08 +04:00
}
type Result struct {
Date time.Time
Total int64
}
db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&results)
```
## Joins
```go
rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
for rows.Next() {
2014-09-16 04:59:04 +04:00
...
2014-07-18 06:16:08 +04:00
}
db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)
```
## Transactions
2014-07-18 06:16:08 +04:00
All individual save and delete operations are run in a transaction by default.
```go
2014-07-18 06:16:08 +04:00
// begin
tx := db.Begin()
// rollback
tx.Rollback()
// commit
tx.Commit()
```
2014-07-18 06:16:08 +04:00
## Scopes
```go
func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
2014-09-16 04:59:04 +04:00
return db.Where("amount > ?", 1000)
2014-07-18 06:16:08 +04:00
}
func PaidWithCreditCard(db *gorm.DB) *gorm.DB {
2014-09-16 04:59:04 +04:00
return db.Where("pay_mode_sign = ?", "C")
2014-07-18 06:16:08 +04:00
}
func PaidWithCod(db *gorm.DB) *gorm.DB {
2014-09-16 04:59:04 +04:00
return db.Where("pay_mode_sign = ?", "C")
2014-07-18 06:16:08 +04:00
}
func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
2014-09-16 04:59:04 +04:00
return func (db *gorm.DB) *gorm.DB {
return db.Scopes(AmountGreaterThan1000).Where("status in (?)", status)
}
2014-07-18 06:16:08 +04:00
}
db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)
// Find all credit card orders and amount greater than 1000
db.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)
// Find all COD orders and amount greater than 1000
db.Scopes(OrderStatus([]string{"paid", "shipped"})).Find(&orders)
// Find all paid, shipped orders
```
2013-11-03 06:09:56 +04:00
## Callbacks
2013-10-27 17:37:31 +04:00
2014-07-18 06:16:08 +04:00
Callbacks are methods defined on the pointer of struct.
If any callback returns an error, gorm will stop future operations and rollback all changes.
2013-11-03 06:09:56 +04:00
2014-07-18 06:16:08 +04:00
Here is the list of all available callbacks:
(listed in the same order in which they will get called during the respective operations)
2013-11-03 06:09:56 +04:00
### Creating An Object
2013-11-03 06:09:56 +04:00
2013-11-24 04:29:56 +04:00
```go
BeforeSave
BeforeCreate
// save before associations
// save self
// save after associations
AfterCreate
AfterSave
```
### Updating An Object
2013-11-24 04:29:56 +04:00
```go
BeforeSave
BeforeUpdate
// save before associations
// save self
// save after associations
AfterUpdate
AfterSave
```
### Destroying An Object
2013-11-24 04:29:56 +04:00
```go
BeforeDelete
// delete self
AfterDelete
```
2013-12-30 08:46:37 +04:00
### After Find
```go
2014-07-18 06:16:08 +04:00
// load data from database
2013-12-30 08:46:37 +04:00
AfterFind
```
2014-07-18 06:16:08 +04:00
### Example
2013-11-15 13:27:16 +04:00
2013-11-03 06:09:56 +04:00
```go
func (u *User) BeforeUpdate() (err error) {
2014-09-16 04:59:04 +04:00
if u.readonly() {
err = errors.New("read only user")
}
return
2013-11-03 06:09:56 +04:00
}
2013-11-11 15:06:26 +04:00
2014-07-18 06:16:08 +04:00
// Rollback the insertion if user's id greater than 1000
2013-11-11 15:06:26 +04:00
func (u *User) AfterCreate() (err error) {
2014-09-16 04:59:04 +04:00
if (u.Id > 1000) {
err = errors.New("user id is already greater than 1000")
}
return
2013-11-11 15:06:26 +04:00
}
2013-11-03 06:09:56 +04:00
```
2013-10-27 17:37:31 +04:00
2014-07-18 06:16:08 +04:00
As you know, save/delete operations in gorm are running in a transaction,
This is means if changes made in the transaction is not visiable unless it is commited,
So if you want to use those changes in your callbacks, you need to run SQL in same transaction.
Fortunately, gorm support pass transaction to callbacks as you needed, you could do it like this:
2013-11-24 04:29:56 +04:00
```go
func (u *User) AfterCreate(tx *gorm.DB) (err error) {
2014-09-16 04:59:04 +04:00
tx.Model(u).Update("role", "admin")
return
2013-11-24 04:29:56 +04:00
}
```
## Specifying The Table Name
2013-11-01 11:01:39 +04:00
2013-11-03 07:32:25 +04:00
```go
2014-07-18 06:16:08 +04:00
// Create `deleted_users` table with struct User's definition
2013-10-28 16:27:25 +04:00
db.Table("deleted_users").CreateTable(&User{})
2013-11-03 06:09:56 +04:00
2013-10-28 16:27:25 +04:00
var deleted_users []User
db.Table("deleted_users").Find(&deleted_users)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM deleted_users;
2013-10-28 16:27:25 +04:00
2013-11-03 06:09:56 +04:00
db.Table("deleted_users").Where("name = ?", "jinzhu").Delete()
//// DELETE FROM deleted_users WHERE name = 'jinzhu';
```
2013-10-28 17:52:22 +04:00
### Specifying The Table Name For A Struct Permanently with TableName
```go
type Cart struct {
}
func (c Cart) TableName() string {
2014-09-16 04:59:04 +04:00
return "shopping_cart"
}
2013-11-06 18:20:26 +04:00
func (u User) TableName() string {
2014-09-16 04:59:04 +04:00
if u.Role == "admin" {
return "admin_users"
} else {
return "users"
}
2013-11-06 18:20:26 +04:00
}
```
2014-07-18 06:16:08 +04:00
## Error Handling
2013-11-18 10:35:44 +04:00
```go
2014-07-18 06:16:08 +04:00
query := db.Where("name = ?", "jinzhu").First(&user)
query := db.First(&user).Limit(10).Find(&users)
// query.Error will return the last happened error
2013-11-18 10:35:44 +04:00
2014-07-18 06:16:08 +04:00
// So you could do error handing in your application like this:
if err := db.Where("name = ?", "jinzhu").First(&user).Error; err != nil {
2014-09-16 04:59:04 +04:00
// error handling...
2013-11-18 10:35:44 +04:00
}
2014-07-18 06:16:08 +04:00
// 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()
2013-11-18 10:35:44 +04:00
2014-07-18 06:16:08 +04:00
if db.Model(&user).Related(&credit_card).RecordNotFound() {
2014-09-16 04:59:04 +04:00
// no credit card found error handling
2013-11-18 10:35:44 +04:00
}
```
2013-11-11 13:50:27 +04:00
## Logger
2014-07-18 06:16:08 +04:00
Gorm has built-in logger support
2013-11-11 13:50:27 +04:00
```go
2014-07-18 06:16:08 +04:00
// Enable Logger
2013-11-11 13:50:27 +04:00
db.LogMode(true)
2014-01-03 15:23:41 +04:00
2014-07-18 06:16:08 +04:00
// Diable Logger
2013-11-11 13:50:27 +04:00
db.LogMode(false)
2014-07-18 06:16:08 +04:00
// Debug a single operation
2013-11-11 13:50:27 +04:00
db.Debug().Where("name = ?", "jinzhu").First(&User{})
```
2014-07-18 06:16:08 +04:00
![logger](https://raw.github.com/jinzhu/gorm/master/images/logger.png)
2013-11-17 09:22:09 +04:00
2014-07-18 06:16:08 +04:00
### Customize Logger
2014-06-01 02:12:31 +04:00
```go
2014-07-18 06:16:08 +04:00
// 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))
2014-06-01 02:12:31 +04:00
```
2014-07-18 06:16:08 +04:00
## Existing Schema
2013-10-28 07:24:51 +04:00
2014-07-18 06:16:08 +04:00
If you have an existing database schema, and the primary key field is different from `id`, you can add a tag to the field structure to specify that this field is a primary key.
2013-11-03 06:09:56 +04:00
```go
2014-07-18 06:16:08 +04:00
type Animal struct {
2015-03-11 12:40:54 +03:00
AnimalId int64 `gorm:"primary_key"`
2014-11-17 12:38:32 +03:00
Birthday time.Time `sql:"DEFAULT:current_timestamp"`
Name string `sql:"default:'galeone'"`
2014-09-16 04:59:04 +04:00
Age int64
}
2013-10-27 17:37:31 +04:00
```
2014-10-07 18:33:57 +04:00
If your column names differ from the struct fields, you can specify them like this:
```go
type Animal struct {
2015-03-11 12:40:54 +03:00
AnimalId int64 `gorm:"column:beast_id;primary_key"`
2014-10-07 18:33:57 +04:00
Birthday time.Time `gorm:"column:day_of_the_beast"`
Age int64 `gorm:"column:age_of_the_beast"`
}
```
2015-03-11 12:40:54 +03:00
## Composite Primary Key
```go
2015-03-11 12:40:54 +03:00
type Product struct {
ID string `gorm:"primary_key"`
LanguageCode string `gorm:"primary_key"`
}
```
2015-03-09 12:22:16 +03:00
## Database Indexes & Foreign Key
```go
// Add foreign key
// 1st param : foreignkey field
// 2nd param : destination table(id)
// 3rd param : ONDELETE
// 4th param : ONUPDATE
db.Model(&User{}).AddForeignKey("user_id", "destination_table(id)", "CASCADE", "RESTRICT")
// Add index
db.Model(&User{}).AddIndex("idx_user_name", "name")
// Multiple column index
db.Model(&User{}).AddIndex("idx_user_name_age", "name", "age")
// Add unique index
db.Model(&User{}).AddUniqueIndex("idx_user_name", "name")
// Multiple column unique index
db.Model(&User{}).AddUniqueIndex("idx_user_name_age", "name", "age")
// Remove index
db.Model(&User{}).RemoveIndex("idx_user_name")
```
2015-03-11 12:40:54 +03:00
## Default values
If you have defined a default value in the `sql` tag (see the struct Animal above) the generated create/update SQl will ignore these fields if is set blank data.
Eg.
```go
db.Create(&Animal{Age: 99, Name: ""})
```
The generated query will be:
```sql
INSERT INTO animals("age") values('99');
```
The same thing occurs in update statements.
2014-07-18 06:16:08 +04:00
## More examples with query chain
2013-10-27 18:18:06 +04:00
2013-11-03 06:09:56 +04:00
```go
2013-10-27 18:18:06 +04:00
db.First(&first_article).Count(&total_count).Limit(10).Find(&first_page_articles).Offset(10).Find(&second_page_articles)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM articles LIMIT 1; (first_article)
2013-11-15 13:27:16 +04:00
//// SELECT count(*) FROM articles; (total_count)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM articles LIMIT 10; (first_page_articles)
//// SELECT * FROM articles LIMIT 10 OFFSET 10; (second_page_articles)
2013-10-27 18:18:06 +04:00
2013-11-15 13:27:16 +04:00
2013-11-03 06:09:56 +04:00
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)
2013-10-27 18:18:06 +04:00
2013-11-15 13:27:16 +04:00
// 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")
2014-07-18 06:16:08 +04:00
// Search with shared conditions for different tables
2013-11-03 06:09:56 +04:00
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)
2013-10-27 18:18:06 +04:00
2013-11-15 13:27:16 +04:00
// Search with shared conditions from different tables with specified table
db.Where("mail_type = ?", "TEXT").Find(&users1).Table("deleted_users").Find(&users2)
2013-11-03 06:09:56 +04:00
//// SELECT * FROM users WHERE mail_type = 'TEXT'; (users1)
//// SELECT * FROM deleted_users WHERE mail_type = 'TEXT'; (users2)
2013-10-28 16:27:25 +04:00
2013-10-30 11:33:34 +04:00
2014-07-18 06:16:08 +04:00
// FirstOrCreate example
2013-11-15 13:27:16 +04:00
db.Where("email = ?", "x@example.org").Attrs(User{RegisteredIp: "111.111.111.111"}).FirstOrCreate(&user)
//// SELECT * FROM users WHERE email = 'x@example.org';
2014-07-18 06:16:08 +04:00
//// INSERT INTO "users" (email,registered_ip) VALUES ("x@example.org", "111.111.111.111") // if record not found
2013-10-27 18:18:06 +04:00
```
2013-10-26 11:18:44 +04:00
## TODO
2015-02-24 12:11:35 +03:00
* db.Select("Languages", "Name").Update(&user)
db.Omit("Languages").Update(&user)
* Auto migrate indexes
2014-01-03 10:54:47 +04:00
* Github Pages
2014-06-01 02:12:31 +04:00
* AlertColumn, DropColumn
2015-02-24 12:11:35 +03:00
* R/W Splitting, Validation
2013-10-25 12:24:29 +04:00
2013-10-26 11:18:44 +04:00
# Author
2013-10-25 12:24:29 +04:00
2013-11-03 06:09:56 +04:00
**jinzhu**
2013-10-25 12:24:29 +04:00
2013-10-26 11:18:44 +04:00
* <http://github.com/jinzhu>
* <wosmvp@gmail.com>
* <http://twitter.com/zhangjinzhu>
2013-11-12 03:13:58 +04:00
## License
2015-01-05 03:58:26 +03:00
Released under the [MIT License](https://github.com/jinzhu/gorm/blob/master/License).
2014-01-04 09:38:41 +04:00
[![GoDoc](https://godoc.org/github.com/jinzhu/gorm?status.png)](http://godoc.org/github.com/jinzhu/gorm)