CRUD обычно относится к операциям добавления, удаления, изменения и запроса базы данных. В этой статье подробно описано, как использовать GORM для реализации операций создания, запроса, обновления и удаления.
Сначала определите модель и соединение с базой данных:
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"os"
"time"
)
type Student struct {
gorm.Model
Name string
Age uint8
Birthday time.Time
}
func main() {
// Конфигурация журнала
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io Writer (цель вывода журнала, префикс и содержимое журнала - примечание переводчика)
logger.Config{
SlowThreshold: time.Second, // медленный SQL порог
LogLevel: logger.Info, // Уровень журнала — информация
IgnoreRecordNotFoundError: true, // Игнорировать ошибку ErrRecordNotFound (запись не найдена)
Colorful: true, // Цветная печать
},
)
dsn := "root:123456@tcp(127.0.0.1:3306)/db1?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
if err != nil {
panic(err) // Если в библиотеке данных нет существования, будет сообщено об ошибке.
}
db.AutoMigrate(&Student{})
}
user := Student{Name: «Джарвис», Age: 18, Birthday: time.Now()}
result := db.Create(&user) // проходитьданныеизприходит указательсоздавать
fmt.Println(user.ID) // Возвращает первичный ключ вставленных данных
fmt.Println(result.Error) // возвращаться error
fmt.Println(result.RowsAffected) // возвращатьсявставить записьизполоскачисло
Создает запись и обновляет данные поля.
student := Student{Name: «Джарвис», Age: 19, Birthday: time.Now()}
db.Select("Name", "Age", "CreatedAt").Create(&student)
// INSERT INTO `students` (`created_at`,`updated_at`,`name`,`age`) VALUES ('2024-01-10 21:05:31.507','2024-01-10 21:05:31.507','Джарвис',19)
Создает запись, а также игнорирует значения полей, переданные для пропуска.
student := Student{Name: "dlrb", Age: 20, Birthday: time.Now()}
db.Omit("Name", "Age", "CreatedAt").Create(&student)
// INSERT INTO `students` (`updated_at`,`deleted_at`,`birthday`) VALUES ('2024-01-10 21:13:49.053',NULL,'2024-01-10 21:13:49.052')
Чтобы эффективно вставлять большое количество записей, Воля a slice
перешел к Create
метод. GORM Воля генерирует один оператор SQL для вставки всех данных и обратного заполнения значения первичного ключа, крюк Метод также будет называться。
t, _ := time.Parse("2024-01-10", "1998-08-18")
var student = []Student{
{Name: «Одноклассники Сяо Ай», Birthday: t},
{Name: «Одноклассник Сяосинь», Birthday: t},
{Name: «Одноклассник Сяобин», Birthday: t},
{Name: «Одноклассник Сяофан», Birthday: t},
}
db.Create(&student)
for _, user := range student {
fmt.Println(user.ID)
}
/*
Поскольку значение даты и времени версии Mysql5.7 и выше не может быть «0000-00-00». 00:00:00',
//Метод обработки:
Изменить mysql.ini
существуют[mysqld]Добавить объект:
sql_mode=NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO
*/
использовать CreateInBatches
При создании в партиях можно указать количество каждой партии, например:
var student [20]Student
t, _ := time.Parse("2024-01-10", "1998-08-18")
for i, _ := range student {
student[i].Name = fmt.Sprintf("Число Джарвиса %d", i)
student[i].Birthday = t
}
fmt.Println(student)
db.CreateInBatches(&student, 10)
Upsert и Create With Associations Пакетная вставка также поддерживается.
Уведомление использовать
CreateBatchSize
Инициализация опции GORM Когда все творение иamp; ассоциацияINSERT
Все Воля следуют этому варианту
// вставка ассоциации
д Б, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
CreateBatchSize: 1000,
})
db := db.Session(&gorm.Session{CreateBatchSize: 1000})
users = [5000]User{{Name: "jinzhu", Pets: []Pet{pet1, pet2, pet3}}...}
db.Create(&users)
// INSERT INTO users xxx (5 batches)
// INSERT INTO pets xxx (15 batches)
GORM Разрешены определяемые пользователем перехваты: BeforeSave
, BeforeCreate
, AfterSave
, AfterCreate
Создать Если вы хотите использовать метод крючка, нажмите ссылку Hooks Подробности о жизненном цикле в
// в основном
db.Create(&Student{
Name: «Джарвис»,
Birthday: time.Now(),
})
// Вставьте предыдущую функцию крюка
func (u *Student) BeforeCreate(tx *gorm.DB) (err error) {
fmt.Println("Студент вставлен")
return
}
Если вы хотите пропустить крюк
Методы, которые вы можете использовать SkipHooks
Режим сеанса, например:
db.Session(&gorm.Session{SkipHooks: true}).Create(&student)
db.Session(&gorm.Session{SkipHooks: true}).Create(&student)
db.Session(&gorm.Session{SkipHooks: true}).CreateInBatches(student, 100)
GORM поддержка на основе map[string]interface{}
и []map[string]interface{}{}
Создайте запись, например:
// Здесь нельзя указать день рождения, поскольку он имеет значение null.
db.Model(&Student{}).Create(map[string]interface{}{
"Name": "Джарвис_001", "Age": 18,
})
// batch insert from `[]map[string]interface{}{}`
db.Model(&Student{}).Create([]map[string]interface{}{
{"Name": "Джарвис_002", "Age": 18},
{"Name": "Джарвис_003", "Age": 20},
})
Уведомление: в соответствии с map При создании записи ассоциация не будет вызываться, и первичный ключ не будет заполняться автоматически.
GORM позволятьиспользовать SQL Данные вставки выражения, есть два способа достижения этой цели. в соответствии с map[string]interface{}
или пользовательский тип данных Создайте, например:
// проходить map Создать запись
db.Model(User{}).Create(map[string]interface{}{
"Name": "jinzhu",
"Location": clause.Expr{SQL: "ST_PointFromText(?)", Vars: []interface{}{"POINT(100 100)"}},
})
// INSERT INTO `users` (`name`,`location`) VALUES ("jinzhu",ST_PointFromText("POINT(100 100)"));
// ввестипользовательский тип Создать запись
type Location struct {
X, Y int
}
// Scan Метод реализован sql.Scanner интерфейс
func (loc *Location) Scan(v interface{}) error {
// Scan a value into struct from database driver
}
func (loc Location) GormDataType() string {
return "geometry"
}
func (loc Location) GormValue(ctx context.Context, db *gorm.DB) clause.Expr {
return clause.Expr{
SQL: "ST_PointFromText(?)",
Vars: []interface{}{fmt.Sprintf("POINT(%d %d)", loc.X, loc.Y)},
}
}
type User struct {
Name string
Location Location
}
db.Create(&User{
Name: "jinzhu",
Location: Location{X: 100, Y: 100},
})
// INSERT INTO `users` (`name`,`location`) VALUES ("jinzhu",ST_PointFromText("POINT(100 100)"))
при создании ассоциаций,не равно нулю в значении ассоциации значение, эти ассоциации будут упадок и их Hook
Метод также будет называться
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
type User struct {
gorm.Model
Name string
CreditCard CreditCard
}
db.Create(&User{
Name: "jinzhu",
CreditCard: CreditCard{Number: "411111111111"}
})
// INSERT INTO `users` ...
// INSERT INTO `credit_cards` ...
Вы также можете пройти Select
、 Omit
Пропустить объединение сохранить,Пример:
db.Omit("CreditCard").Create(&user)
// Пропустить все ассоциации
db.Omit(clause.Associations).Create(&user)
Вы можете использовать тег default
Определите значения по умолчанию для полей, например:
type User struct {
ID int64
Name string `gorm:"default:galeone"`
Age int64 `gorm:"default:18"`
}
При вставке записей в базу данных значение по умолчанию будет использоваться Значение заполнения нулевое значение поля
Уведомление Для утверждения значение по поле по умолчанию, картина
0
、''
、false
ждатьнулевое значение не сохраняется в библиотеке данных. Вам нужно использовать тип указателя или Scanner/Valuer Чтобы избежать этой проблемы, например:
type User struct {
gorm.Model
Name string
Age *int `gorm:"default:18"`
Active sql.NullBool `gorm:"default:true"`
}
Уведомление Чтобы база данных имела фиктивные/сгенерированные значения по умолчанию, вы должны установить
default
Этикетка. Быть в Пропустить значение при миграции по Определение по умолчанию, вы можете использоватьdefault:(-)
,Например:
type User struct {
ID string `gorm:"default:uuid_generate_v3()"` // db func
FirstName string
LastName string
Age uint8
FullName string `gorm:"->;type:GENERATED ALWAYS AS (concat(firstname,' ',lastname));default:(-);"`
}
использоватьвиртуальный/генерироватьизценитьчас,Возможно, вам придется отключить его, создавать,возобновлять разрешения,Проверять Разрешения на уровне поля Получить подробности
GORM обеспечивает совместимую поддержку Upsert для различных баз данных.
иногда вставляйте данные,Сообщить о конфликте первичного ключа,иметьupsert Вы можете как обновить данные, так и вставить данные, чтобы решить эту проблему. Если первичный ключ существует, обновите его.
import "gorm.io/gorm/clause"
// Когда существуют конфликты, ничего не делайте
db.Clauses(clause.OnConflict{DoNothing: true}).Create(&user)
// существовать`id`В конфликте,Воля Списоквозобновлятьдлязначение по умолчанию
db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
DoUpdates: clause.Assignments(map[string]interface{}{"role": "user"}),
}).Create(&users)
// MERGE INTO "users" USING *** WHEN NOT MATCHED THEN INSERT *** WHEN MATCHED THEN UPDATE SET ***; SQL Server
// INSERT INTO `users` *** ON DUPLICATE KEY UPDATE ***; MySQL
// использоватьSQLзаявление
db.Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "id"}},
DoUpdates: clause.Assignments(map[string]interface{}{"count": gorm.Expr("GREATEST(count, VALUES(count))")}),
}).Create(&users)
// INSERT INTO `users` *** ON DUPLICATE KEY UPDATE `count`=GREATEST(count, VALUES(count));
// При конфликте существующих `id` в столбце «Воля возобновлять» указывается новое значение.
db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "id"}},
DoUpdates: clause.AssignmentColumns([]string{"name", "age"}),
}).Create(&users)
// MERGE INTO "users" USING *** WHEN NOT MATCHED THEN INSERT *** WHEN MATCHED THEN UPDATE SET "name"="excluded"."name"; SQL Server
// INSERT INTO "users" *** ON CONFLICT ("id") DO UPDATE SET "name"="excluded"."name", "age"="excluded"."age"; PostgreSQL
// INSERT INTO `users` *** ON DUPLICATE KEY UPDATE `name`=VALUES(name),`age=VALUES(age); MySQL
// В случае существования конфликтов возобновить все столбцы, кроме первичного ключа, до новых значений ----》Это часто используется.
db.Clauses(clause.OnConflict{
UpdateAll: true,
}).Create(&users)
// INSERT INTO "users" *** ON CONFLICT ("id") DO UPDATE SET "name"="excluded"."name", "age"="excluded"."age", ...;
Вы также можете просмотреть Расширенный запрос в FirstOrInit
、FirstOrCreate
Проверять Родной SQL и конструктор Получить более подробную информацию
GORM предоставил First
、Take
、Last
Метод для получения одного объекта из базы данных. При запросе к базе данных он добавляет LIMIT 1
состояние,ибезиметьоказатьсяво время записи,это Уилл возвращаться ErrRecordNotFound
ошибка
var student Student
// получить Первую запись (в порядке возрастания первичного ключа)
db.First(&student)
// SELECT * FROM users ORDER BY id LIMIT 1;
// получить запись без обозначенного поля сортировки
db.Take(&student)
//SELECT * FROM users LIMIT 1;
// получить Последнюю запись (в порядке убывания первичного ключа)
db.Last(&student)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;
fmt.Println(student)
result := db.First(&student)
fmt.Println(result.RowsAffected) // возвращатьсяоказатьсяиз Записыватьчисло
fmt.Println(result.Error) // returns error or nil
// исследовать возвращатьсяизошибкаданетдабезоказаться Записыватьизошибка ErrRecordNotFound ошибка
fmt.Println(errors.Is(result.Error, gorm.ErrRecordNotFound))
еслиты хочешь избежать
ErrRecordNotFound
ошибка,ты можешьиспользоватьFind
,напримерdb.Limit(1).Find(&user)
,Find
метод приемлемstructиsliceизданные。
First
и Last
Уилл в соответствии Сортировка по первичному ключу соответственно Запрос первой и последней записи. только в цель struct дауказательили ВОЗпроходить db.Model()
обозначение model Этот метод эффективен только тогда, когда . Дополнительно, если это актуально model Первичный ключ не определен, затем Воля нажмите model Сортировка по первому полю. Например:
var user User
var users []User
// works because destination struct is passed in
// работает нормально, потому что целевая структура была передана
db.First(&user)
// SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1
// works because model is specified using `db.Model()`
// использоватьmap, нужно обозначение с этой таблицей ассоциации
result := map[string]interface{}{}
db.Model(&User{}).First(&result)
// SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1
// doesn't work-->безобозначениеModel,неверный
result = map[string]interface{}{}
db.Table("users").First(&result)
// works with Take,использоватьTakeвступить в силу
result = map[string]interface{}{}
db.Table("users").Take(&result)
// no primary key defined, results will be ordered by first field (i.e., `Code`)
// Если первичного ключа нет, сортируйте по первому полю.
type Language struct {
Code string
Name string
}
db.First(&Language{})
// SELECT * FROM `languages` ORDER BY `languages`.`code` LIMIT 1
еслипервичный ключдачислотип шрифта,Вы можете использовать в соответствиисостояние чтобы получить объект. При передаче строковых параметров требуется особая осторожность. SQL Проблема с впрыском, Проверить Безопасность Получить подробности.
var user User
var users []User
db.First(&user, 10)
// SELECT * FROM users WHERE id = 10;
db.First(&user, "10")
// SELECT * FROM users WHERE id = 10;
db.Find(&users, []int{1,2,3})
// SELECT * FROM users WHERE id IN (1,2,3);
fmt.Println(user)
fmt.Println(users)
Если первичный ключ представляет собой строку (например, например uuid),Запрос Волябыло написано так:
db.First(&user, "id = ?", "1b74413f-f3b8-409f-ac47-e8c062e3472a")
// SELECT * FROM users WHERE id = "1b74413f-f3b8-409f-ac47-e8c062e3472a";
When the destination object has a primary value, the primary key will be used to build the condition, for example:
//Когда целевой объект имеет значение первичного ключа,первичный ключ Воляиспользуется длястроитьсостояние
var user = User{ID: 10}
db.First(&user)
// SELECT * FROM users WHERE id = 10;
var result User
db.Model(User{ID: 10}).First(&result)
// SELECT * FROM users WHERE id = 10;
var student []Student
// Get all records
result := db.Find(&student)
// SELECT * FROM `students` WHERE `students`.`deleted_at` IS NULL
fmt.Println(result.RowsAffected) // возвращатьсяоказатьсяиз Записыватьсчитатьчисло,ждать В“лен (студент)”
fmt.Println(result.Error) // возвращает ошибку или ноль
var student Student
// определение lastWeek и today
lastWeek := time.Now().AddDate(0, 0, -7) // неделю назад
today := time.Now() // текущее время
// Get first matched record
db.Where("name = ?", "Джарвис").First(&student)
// SELECT * FROM `students` WHERE name = 'Джарвис' AND `students`.`deleted_at` IS NULL ORDER BY `student`id` LIMIT 1
// Get all matched records
db.Where("name <> ?", "Джарвис").Find(&student)
// SELECT * FROM `students` WHERE name <> 'Джарвис' AND `students`.`deleted_at` IS NULL AND `students`.` = 25
// IN
db.Where("name IN ?", []string{«Джарвис», "Джарвис 2"}).Find(&student)
// SELECT * FROM `students` WHERE name IN ('Джарвис','Джарвис 2') AND `students`.`deleted_at` IS NULL ANDents`.`id` = 25
// LIKE
db.Where("name LIKE ?", "%Джарвис%").Find(&student)
// SELECT * FROM `students` WHERE name LIKE '% Джарвис%' AND `students`.`deleted_at` IS NULL AND `student`id` = 25
// AND
db.Where("name = ? AND age >= ?", «Джарвис», "22").Find(&student)
// SELECT * FROM `students` WHERE (name = 'Джарвис' AND age >= '22') AND `students`.`deleted_at` IS NULLD `students`.`id` = 25
// Time
db.Where("updated_at > ?", lastWeek).Find(&student)
// SELECT * FROM `students` WHERE updated_at > '2024-01-03 23:05:18.068' AND `students`.`deleted_at` IS NULL AND `students`.`id` = 25
// BETWEEN
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&student)
// SELECT * FROM `students` WHERE (created_at BETWEEN '2024-01-03 23:05:18.068' AND '2024-01-10 23:05:18.068') AND `students`.`deleted_at` IS NULL AND `students`.`id` = 25
var student Student
// Struct
db.Where(&Student{Name: «Джарвис», Age: 20}).First(&student)
// SELECT * FROM `students` WHERE `students`.`name` = 'Джарвис' AND `students`.`age` = 20 AND `students`eleted_at` IS NULL ORDER BY `students`.`id` LIMIT 1
// Map
db.Where(map[string]interface{}{"name": «Джарвис», "age": 20}).Find(&student)
// SELECT * FROM `students` WHERE `age` = 20 AND `name` = 'Джарвис' AND `students`.`deleted_at` IS NULL
// Slice of primary keys
db.Where([]int64{20, 21, 22}).Find(&student)
// SELECT * FROM `students` WHERE `students`.`id` IN (20,21,22) AND `students`.`deleted_at` IS NULL
NOTE When querying with struct, GORM will only query with non-zero fields, that means if your field’s value is
0
,''
,false
or other zero values, it won’t be used to build query conditions, for example:
var student Student
// При использовании структуры как Запроссостояние, gorm будет запрашивать только поля, отличные от 0, если поле равно `0`, `''`, `false` or other zero значения, это поле не использоватьсястроить Запроссостояние
db.Where(&Student{Name: «Джарвис», Age: 0}).Find(&student)
// SELECT * FROM `students` WHERE `students`.`name` = 'Джарвис' AND `students`.`deleted_at` IS NULL
Быть в Запроссостояние Содержитнулевое значение, canusemap, карта Воля содержит все ключевые значения как Запроссостояние,Пример:
// Если вы хотите, чтобы существование Запрос содержало 0поля, вы можете сделать это с помощью usemap
db.Where(map[string]interface{}{"Name": «Джарвис», "Age": 0}).Find(&student)
// SELECT * FROM `students` WHERE `Age` = 0 AND `Name` = 'Джарвис' AND `students`.`deleted_at` IS NULL
For more details, see Specify Struct search fields.
использовать struct При поиске вы можете ввести названия полей, связанных с Волей, или dbname перешел к 'Where()' Приходитьобозначениехотетьсуществовать Запроссостояниесерединаиспользоватьизструктуравкакой конкретныйценить,Например:
//существоватьиспользоватьstruct При поиске вы можете использовать имя связанного поля Воли или имя данной библиотеки, перешел к`Where(),Приходитьобозначениесуществовать Запроссостояниесерединаиспользоватьstructвкакой конкретныйценить`
db.Where(&Student{Name: "Джарвис"}, "name", "Age").Find(&student)
// SELECT * FROM `students` WHERE `students`.`name` = 'Джарвис' AND `students`.`age` = 0 AND `students`.leted_at` IS NULL
db.Where(&Student{Name: "Джарвис"}, "Age").Find(&student)
// SELECT * FROM `students` WHERE `students`.`age` = 0 AND `students`.`deleted_at` IS NULL AND `students`.`id` = 25
Запроссостояние Это можно сделать аналогичноWhereиз Способв соответствииприезжать'First'и'Find'ждатьметодсередина
// Если это первичный ключ без формы, в соответствии с Первичный ключ получения записи
db.First(&Student{}, "id = ?", "string_primary_key")
// SELECT * FROM `students` WHERE id = 'string_primary_key' AND `students`.`deleted_at` IS NULL ORDER BY `students`.`id` LIMIT 1
// Plain SQL
db.Find(&Student{}, "name = ?", "jinzhu")
// SELECT * FROM `students` WHERE name = 'jinzhu' AND `students`.`deleted_at` IS NULL
db.Find(&Student{}, "name <> ? AND age > ?", "jinzhu", 20)
// SELECT * FROM `students` WHERE (name <> 'jinzhu' AND age > 20) AND `students`.`deleted_at` IS NULL
// Struct
db.Find(&Student{}, Student{Age: 20})
// SELECT * FROM `students` WHERE `students`.`age` = 20 AND `students`.`deleted_at` IS NULL
// Map
db.Find(&Student{}, map[string]interface{}{"age": 20})
// SELECT * FROM `students` WHERE `age` = 20 AND `students`.`deleted_at` IS NULL
Build NOT conditions, works similar to Where
строитьNOTсостояние,Принцип работы тот же, что и Где.
var student Student
db.Not("name = ?", "Джарвис").First(&student)
// SELECT * FROM `students` WHERE NOT name = 'Джарвис' AND `students`.`deleted_at` IS NULL ORDER BY `stuts`.`id` LIMIT 1
// Not In
db.Not(map[string]interface{}{"name": []string{«Джарвис», "Джарвис 2"}}).Find(&student)
// SELECT * FROM `students` WHERE `name` NOT IN ('Джарвис','Джарвис 2') AND `students`.`deleted_at` IS NU `students`.`id` = 1
// Struct
db.Not(Student{Name: «Джарвис», Age: 18}).First(&student)
// SELECT * FROM `students` WHERE (`students`.`name` <> 'Джарвис' AND `students`.`age` <> 18) AND `stude`.`deleted_at` IS NULL AND `students`.`id` = 1 ORDER BY `students`.`id` LIMIT 1
// Not In slice of primary keys
db.Not([]int64{1, 2, 3}).First(&student)
// SELECT * FROM `students` WHERE `students`.`id` NOT IN (1,2,3) AND `students`.`deleted_at` IS NULL AND `students`.`id` = 1 ORDER BY `students`.`id` LIMIT 1
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&student)
// SELECT * FROM `students` WHERE (role = 'admin' OR role = 'super_admin') AND `students`.`deleted_at` IS NULL AND `students`.`id` = 4
// Struct
db.Where("name = 'jinzhu'").Or(Student{Name: "Джарвис 2", Age: 18}).Find(&student)
// SELECT * FROM `students` WHERE (name = 'jinzhu' OR (`students`.`name` = 'Джарвис 2' AND `students`.`a = 18)) AND `students`.`deleted_at` IS NULL AND `students`.`id` = 4
// Map
db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "Джарвис 2", "age": 18}).Find(&student)
// SELECT * FROM `students` WHERE (name = 'jinzhu' OR (`age` = 18 AND `name` = 'Джарвис 2')) AND `studen.`deleted_at` IS NULL AND `students`.`id` = 4
For more complicated SQL queries. please also refer to Group Conditions in Advanced Query.
`Select` позволяет вам отображать поля из библиотеки данных. в противном случае,GORMВоляпо умолчаниювыбиратьсклепиметь Поле
db.Select("name", "age").Find(&student)
// SELECT `name`,`age` FROM `students` WHERE `students`.`deleted_at` IS NULL
db.Select([]string{"name", "age"}).Find(&student)
// SELECT `name`,`age` FROM `students` WHERE `students`.`deleted_at` IS NULL
db.Table("students").Select("COALESCE(age,?)", 42).Rows()
// SELECT COALESCE(age,42) FROM `students`
Also check out Smart Select Fields
Specify order when retrieving records from the database
обозначениеотданные Библиотека Поискво время записииззаказ
db.Order("age desc, name").Find(&student)
// SELECT * FROM `students` WHERE `students`.`deleted_at` IS NULL ORDER BY age desc, name
// Multiple orders
db.Order("age desc").Order("name").Find(&student)
// SELECT * FROM `students` WHERE `students`.`deleted_at` IS NULL AND `students`.`id` = 35 ORDER BY age desc,name
db.Clauses(clause.OrderBy{
Expression: clause.Expr{SQL: "FIELD(id,?)", Vars: []interface{}{[]int{1, 2, 3}}, WithoutParentheses: true},
}).Find(&Student{})
// SELECT * FROM `students` WHERE `students`.`deleted_at` IS NULL ORDER BY FIELD(id,1,2,3)
Limit
specify the max number of records to retrieve Offset
specify the number of records to skip before starting to return the records
Limit
обозначениехотеть Поискизмаксимум ЗаписыватьчислоOffset
обозначениеначинатьвозвращаться Записывать Дохотетьперепрыгнииз Записыватьчисло
db.Limit(3).Find(&users)
// SELECT * FROM users LIMIT 3;
// Cancel limit condition with -1
db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
// SELECT * FROM users LIMIT 10; (users1)
// SELECT * FROM users; (users2)
db.Offset(3).Find(&users)
// SELECT * FROM users OFFSET 3;
db.Limit(10).Offset(5).Find(&users)
// SELECT * FROM users OFFSET 5 LIMIT 10;
// Cancel offset condition with -1
db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
// SELECT * FROM users OFFSET 10; (users1)
// SELECT * FROM users; (users2)
Refer to Pagination for details on how to make a paginator
type result struct {
Date time.Time
Total int
}
db.Model(&User{}).Select("name, sum(age) as total").Where("name LIKE ?", "group%").Group("name").First(&result)
// SELECT name, sum(age) as total FROM `users` WHERE name LIKE "group%" GROUP BY `name` LIMIT 1
db.Model(&User{}).Select("name, sum(age) as total").Group("name").Having("name = ?", "group").Find(&result)
// SELECT name, sum(age) as total FROM `users` GROUP BY `name` HAVING name = "group"
rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()
defer rows.Close()
for rows.Next() {
...
}
rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Rows()
defer rows.Close()
for rows.Next() {
...
}
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)
Selecting distinct values from the model
Выберите разные значения из модели
db.Distinct("name", "age").Order("name, age desc").Find(&results)
Distinct
works with Pluck
and Count
too
Specify Joins conditions-обозначениесоединятьсостояние
type result struct {
Name string
Email string
}
db.Model(&User{}).Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&result{})
// SELECT users.name, emails.email FROM `users` left join emails on emails.user_id = users.id
rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
for rows.Next() {
...
}
db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)
// multiple joins with parameter
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)
You can use Joins
eager loading associations with a single SQL, for example:
Можетиспользовать'Joins'Приходитьзагрузка против одиночнойSQLизассоциация
db.Joins("Company").Find(&users)
// SELECT `users`.`id`,`users`.`name`,`users`.`age`,`Company`.`id` AS `Company__id`,`Company`.`name` AS `Company__name` FROM `users` LEFT JOIN `companies` AS `Company` ON `users`.`company_id` = `Company`.`id`;
Join with conditions
db.Joins("Company", DB.Where(&Company{Alive: true})).Find(&users)
// SELECT `users`.`id`,`users`.`name`,`users`.`age`,`Company`.`id` AS `Company__id`,`Company`.`name` AS `Company__name` FROM `users` LEFT JOIN `companies` AS `Company` ON `users`.`company_id` = `Company`.`id` AND `Company`.`alive` = true;
For more details, please refer to Preloading (Eager Loading).
You can also use Joins
to join a derived table.
type User struct {
Id int
Age int
}
type Order struct {
UserId int
FinishedAt *time.Time
}
query := db.Table("order").Select("MAX(order.finished_at) as latest").Joins("left join user user on order.user_id = user.id").Where("user.age > ?", 18).Group("order.user_id")
db.Model(&Order{}).Joins("join (?) q on order.finished_at = q.latest", query).Scan(&results)
// SELECT `order`.`user_id`,`order`.`finished_at` FROM `order` join (SELECT MAX(order.finished_at) as latest FROM `order` left join user user on order.user_id = user.id WHERE user.age > 18 GROUP BY `order`.`user_id`) q on order.finished_at = q.latest
Scanning results into a struct works similarly to the way we use Find
--
Волярезультат сканирует в структуру и работает аналогично «Найти».
type Result struct {
Name string
Age int
}
var result Result
db.Table("users").Select("name", "age").Where("name = ?", "Antonio").Scan(&result)
// Raw SQL
db.Raw("SELECT name, age FROM users WHERE name = ?", "Antonio").Scan(&result)
GORM разрешено пройти Select
Конкретные поля выбора метода,еслитысуществоватьприложениесерединачастоиспользовать Эта функция,тытакже Можетопределениеменьшийизструктуратело,реализовать вызов API Автоматически выбирать определенные поля, например:
type User struct {
ID uint
Name string
Age int
Gender string
// Предположим, позже появятся сотни полей...
}
type APIUser struct {
ID uint
Name string
}
// Запрос будет выбран автоматически, когда `id`, `name` Поле
db.Model(&User{}).Limit(10).Find(&APIUser{})
// SELECT `id`, `name` FROM `users` LIMIT 10
Уведомление
QueryFields
модель Уилл в соответствии текущий model Все имена полей select。
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
QueryFields: true,
})
db.Find(&user)
// SELECT `users`.`name`, `users`.`age`, ... FROM `users` // принеси этот вариант
// Session Mode
db.Session(&gorm.Session{QueryFields: true}).Find(&user)
// SELECT `users`.`name`, `users`.`age`, ... FROM `users`
GORM поддерживает множество типов блокировок, таких как:
db.Clauses(clause.Locking{Strength: "UPDATE"}).Find(&users)
// SELECT * FROM `users` FOR UPDATE
db.Clauses(clause.Locking{
Strength: "SHARE",
Table: clause.Table{Name: clause.CurrentTable},
}).Find(&users)
// SELECT * FROM `users` FOR SHARE OF `users`
db.Clauses(clause.Locking{
Strength: "UPDATE",
Options: "NOWAIT",
}).Find(&users)
// SELECT * FROM `users` FOR UPDATE NOWAIT
Проверять Родной SQL и конструктор Получить подробности
Подзапросы могут быть вложены в запросы, GORM позволятьсуществоватьиспользовать *gorm.DB
Создать подзапрос, когда объект используется в качестве параметра
db.Where("amount > (?)", db.Table("orders").Select("AVG(amount)")).Find(&orders)
// SELECT * FROM "orders" WHERE amount > (SELECT AVG(amount) FROM "orders");
subQuery := db.Select("AVG(age)").Where("name LIKE ?", "name%").Table("users")
db.Select("AVG(age) as avgage").Group("name").Having("AVG(age) > (?)", subQuery).Find(&results)
// SELECT AVG(age) as avgage FROM `users` GROUP BY `name` HAVING AVG(age) > (SELECT AVG(age) FROM `users` WHERE name LIKE "name%")
GORM позволяет вам Table
передано в метод FROM пунктиспользоватьребенок Запрос,Например:
db.Table("(?) as u", db.Model(&User{}).Select("name", "age")).Where("age = ?", 18).Find(&User{})
// SELECT * FROM (SELECT `name`,`age` FROM `users`) as u WHERE age = 18
subQuery1 := db.Model(&User{}).Select("name")
subQuery2 := db.Model(&Pet{}).Select("name")
db.Table("(?) as u, (?) as p", subQuery1, subQuery2).Find(&User{})
// SELECT * FROM (SELECT `name` FROM `users`) as u, (SELECT `name` FROM `pets`) as p
использовать Group состояние облегчает написание сложного SQL
db.Where(
db.Where("pizza = ?", "pepperoni").Where(db.Where("size = ?", "small").Or("size = ?", "medium")),
).Or(
db.Where("pizza = ?", "hawaiian").Where("size = ?", "xlarge"),
).Find(&Pizza{}).Statement
// SELECT * FROM `pizzas` WHERE (pizza = "pepperoni" AND (size = "small" OR size = "medium")) OR (pizza = "hawaiian" AND size = "xlarge")
В запросе с несколькими столбцами
db.Where("(name, age, role) IN ?", [][]interface{}{{"jinzhu", 18, "admin"}, {"jinzhu2", 19, "user"}}).Find(&users)
// SELECT * FROM users WHERE (name, age, role) IN (("jinzhu", 18, "admin"), ("jinzhu 2", 19, "user"));
GORM поддерживать sql.NamedArg
и map[string]interface{}{}
Именованные параметры формы, например:
db.Where("name1 = @name OR name2 = @name", sql.Named("name", "jinzhu")).Find(&user)
// SELECT * FROM `users` WHERE name1 = "jinzhu" OR name2 = "jinzhu"
db.Where("name1 = @name OR name2 = @name", map[string]interface{}{"name": "jinzhu"}).First(&user)
// SELECT * FROM `users` WHERE name1 = "jinzhu" OR name2 = "jinzhu" ORDER BY `users`.`id` LIMIT 1
Проверять Родной SQL и конструктор Получить подробности
GORM Разрешить результаты сканирования map[string]interface{}
или []map[string]interface{}
,Не забудьте в это время обозначение Model
или Table
,Например:
result := map[string]interface{}{}
db.Model(&User{}).First(&result, "id = ?", 1)
var results []map[string]interface{}
db.Table("users").Find(&results)
получать Первыйполоскасоответствоватьиз Записывать,или ВОЗв соответствии с Инициализирует экземпляр данного состояния (только поддержка sturct и map состояние)
// не найдено пользователь, затем в соответствии с Инициализирует запись заданного состояния
db.FirstOrInit(&user, User{Name: "non_existing"})
// user -> User{Name: "non_existing"}
// Нашел это `name` = `jinzhu` из user
db.Where(User{Name: "jinzhu"}).FirstOrInit(&user)
// user -> User{ID: 111, Name: "Jinzhu", Age: 18}
// Нашел это `name` = `jinzhu` из user
db.FirstOrInit(&user, map[string]interface{}{"name": "jinzhu"})
// user -> User{ID: 111, Name: "Jinzhu", Age: 18}
еслибезиметьоказаться Записывать,Можетиспользовать Содержит большеизсвойствоизструктурателоинициализация user,Attrs
Нетбудет использоватьсягенерировать Запрос SQL
// не найдено пользователь, затем в соответствии с заданным изостоянием и Attrs инициализация user
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrInit(&user)
// SELECT * FROM USERS WHERE name = 'non_existing' ORDER BY id LIMIT 1;
// user -> User{Name: "non_existing", Age: 20}
// не найдено пользователь, затем в соответствии с заданным изостоянием и Attrs инициализация user
db.Where(User{Name: "non_existing"}).Attrs("age", 20).FirstOrInit(&user)
// SELECT * FROM USERS WHERE name = 'non_existing' ORDER BY id LIMIT 1;
// user -> User{Name: "non_existing", Age: 20}
// Нашел это `name` = `jinzhu` из пользователь, игнорируй Attrs
db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 20}).FirstOrInit(&user)
// SELECT * FROM USERS WHERE name = jinzhu' ORDER BY id LIMIT 1;
// user -> User{ID: 111, Name: "Jinzhu", Age: 18}
несмотря наданетоказаться Записывать,Assign
Атрибут Воля будет присвоен struct, но эти свойства не являются использоватьсягенерировать Запрос SQL и не будет сохранен в базе данных.
// не найдено user,в соответствии ссостояниеи Assign свойствоинициализация struct
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrInit(&user)
// user -> User{Name: "non_existing", Age: 20}
// оказаться `name` = `jinzhu` из Записывать,все еще Уилл возобновлять Assign Связанныйизсвойство
db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 20}).FirstOrInit(&user)
// SELECT * FROM USERS WHERE name = jinzhu' ORDER BY id LIMIT 1;
// user -> User{ID: 111, Name: "Jinzhu", Age: 20}
Get first matched record or create a new one with given conditions (only works with struct, map conditions), RowsAffected
returns created/updated record’s count
// User not found, create a new record with give conditions
result := db.FirstOrCreate(&user, User{Name: "non_existing"})
// INSERT INTO "users" (name) VALUES ("non_existing");
// user -> User{ID: 112, Name: "non_existing"}
// result.RowsAffected // => 0
// Found user with `name` = `jinzhu`
result := db.Where(User{Name: "jinzhu"}).FirstOrCreate(&user)
// user -> User{ID: 111, Name: "jinzhu", "Age": 18}
// result.RowsAffected // => 0
еслибезиметьоказаться Записывать,Можетиспользовать Содержит большеизсвойствоизструктуратело Создать запись,Attrs
Нетбудет использоватьсягенерировать Запрос SQL 。
// не найдено user,в соответствии ссостояниеи Assign свойство Создать запись
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
// SELECT * FROM users WHERE name = 'non_existing' ORDER BY id LIMIT 1;
// INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
// user -> User{ID: 112, Name: "non_existing", Age: 20}
// Нашел это `name` = `jinzhu` из пользователь, игнорируй Attrs
db.Where(User{Name: "jinzhu"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;
// user -> User{ID: 111, Name: "jinzhu", Age: 18}
несмотря наданетоказаться Записывать,Assign
Атрибут Воля будет присвоен struct,и Волярезультатнапиши ответданные Библиотека
// не найдено user,в соответствии ссостояниеи Assign свойство Создать запись
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrCreate(&user)
// SELECT * FROM users WHERE name = 'non_existing' ORDER BY id LIMIT 1;
// INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
// user -> User{ID: 112, Name: "non_existing", Age: 20}
// Нашел это `name` = `jinzhu` из user,все еще Уилл в соответствии с Assign возобновлять Записывать
db.Where(User{Name: "jinzhu"}).Assign(User{Age: 20}).FirstOrCreate(&user)
// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;
// UPDATE users SET age=20 WHERE id = 111;
// user -> User{ID: 111, Name: "jinzhu", Age: 20}
Подсказки оптимизатора используются для управления оптимизатором запросов для выбора определенного плана выполнения запроса, GORM. проходить gorm.io/hints
поставлятьподдерживать,Например:
import "gorm.io/hints"
db.Clauses(hints.New("MAX_EXECUTION_TIME(10000)")).Find(&User{})
// SELECT * /*+ MAX_EXECUTION_TIME(10000) */ FROM `users`
Подсказки индекса позволяют передавать подсказки индекса в базу данных в случае паники планировщика запросов.
import "gorm.io/hints"
db.Clauses(hints.UseIndex("idx_user_name")).Find(&User{})
// SELECT * FROM `users` USE INDEX (`idx_user_name`)
db.Clauses(hints.ForceIndex("idx_user_name", "idx_user_id").ForJoin()).Find(&User{})
// SELECT * FROM `users` FORCE INDEX FOR JOIN (`idx_user_name`,`idx_user_id`)"
ссылка Советы по оптимизатору, указатели, примечания Получить подробности
GORM поддерживатьпроходить ХОРОШОруководить Итерировать
rows, err := db.Model(&User{}).Where("name = ?", "jinzhu").Rows()
defer rows.Close()
for rows.Next() {
var user User
// ScanRows Метод для однострочной записи Воли Сканировать в Структура
db.ScanRows(rows, &user)
// бизнес-логика...
}
Используется для пакетного запроса и обработки записей.
// Каждый раз партия обрабатывается 100 полоска
result := db.Where("processed = ?", false).FindInBatches(&results, 100, func(tx *gorm.DB, batch int) error {
for _, result := range results {
// партияиметь дело соказатьсяиз Записывать
}
tx.Save(&results)
tx.RowsAffected // На этот разпартия Операционное воздействиеиз Записыватьчисло
batch // Batch 1, 2, 3
// есливозвращатьсяошибка прекратит последующие операции партии
return nil
})
result.Error // returned error
result.RowsAffected // весьпартия Операционное воздействиеиз Записыватьчисло
Для операций запроса GORM поддерживать AfterFind
крюк, Запрос позвонит после записи, подробности по ссылке крюк
func (u *User) AfterFind(tx *gorm.DB) (err error) {
if u.Role == "" {
u.Role = "user"
}
return
}
Pluck Используется для сканирования отдельного столбца из библиотеки данных Запрос и Волярезультат на срезы. Если вы хотите Запроснесколько столбцов, вам следует использовать Select
и Scan
var ages []int64
db.Model(&users).Pluck("age", &ages)
var names []string
db.Model(&User{}).Pluck("name", &names)
db.Table("deleted_users").Pluck("name", &names)
// Distinct Pluck
db.Model(&User{}).Distinct().Pluck("Name", &names)
// SELECT DISTINCT `name` FROM `users`
// более одного Списокиз Запрос,должениспользовать `Scan` или ВОЗ `Find`,Например:
db.Select("name", "age").Scan(&users)
db.Select("name", "age").Find(&users)
Scopes
позволятьтыобозначение Обычно используетсяиз Запрос,Вы можете ссылаться на эти Запросы при вызове методов.
func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
return db.Where("amount > ?", 1000)
}
func PaidWithCreditCard(db *gorm.DB) *gorm.DB {
return db.Where("pay_mode_sign = ?", "C")
}
func PaidWithCod(db *gorm.DB) *gorm.DB {
return db.Where("pay_mode_sign = ?", "C")
}
func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
return func (db *gorm.DB) *gorm.DB {
return db.Where("status IN (?)", status)
}
}
db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)
// Найдите все суммы, превышающие 1000 из Заказы по кредитным картам
db.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)
// Найдите все суммы, превышающие 1000 заказ наложенным платежом
db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders)
// Найдите все суммы, превышающие 1000 и заплатилили Отправленныйиз Заказ
Проверять Scopes Получить подробности
Count используется для получения количества совпадающих записей.
var count int64
db.Model(&User{}).Where("name = ?", "jinzhu").Or("name = ?", "jinzhu 2").Count(&count)
// SELECT count(1) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'
db.Model(&User{}).Where("name = ?", "jinzhu").Count(&count)
// SELECT count(1) FROM users WHERE name = 'jinzhu'; (count)
db.Table("deleted_users").Count(&count)
// SELECT count(1) FROM deleted_users;
// Count with Distinct
db.Model(&User{}).Distinct("name").Count(&count)
// SELECT COUNT(DISTINCT(`name`)) FROM `users`
db.Table("deleted_users").Select("count(distinct(name))").Count(&count)
// SELECT count(distinct(name)) FROM deleted_users
// Count with Group
users := []User{
{Name: "name1"},
{Name: "name2"},
{Name: "name3"},
{Name: "name3"},
}
db.Model(&User{}).Group("name").Count(&count)
count // => 3
Save
встречахранилищеиметьполя,Хоть Поледанулевое значение
var student Student
db.First(&student)
student.Name = "Джарвис"
student.Age = 100
db.Save(&student)
// UPDATE `students` SET `created_at`='2024-01-10 21:54:45.79',`updated_at`='2024-01-11 16:01:53.082',`deleted_at`=NULL,`name`='Джарвис',`age`=100,`birthday`='0000-00-00 00:00:00' WHERE `students`.`deleted_at` IS NULL AND ` = 1
когдаиспользовать Update
Обновить один столбецчас,тынуждатьсяхотетьобозначениесостояние,нетно Уилл возвращаться ErrMissingWhereClause
ошибка,Проверять Block Global Updates Получить подробности。когдаиспользовать Понятно Model
метод, а первичный ключ объекта имеет значение, и это значение будет использоватьсястроитьсостояние,Например:
var student Student
// состояниевозобновлять(еслииметьмногополоска,Полныйвозобновлять)
db.Model(&Student{}).Where("active = ?", true).Update("name", "jarvis")
// UPDATE `students` SET `name`='jarvis-01',`updated_at`='2024-01-11 16:17:39.741' WHERE `students`.`deleted_at` IS NULL AND `id` = 1;
// User из ID да `1`
db.First(&student)
db.Model(&student).Update("name", "jarvis-01")
// SELECT * FROM `students` WHERE `students`.`deleted_at` IS NULL AND `students`.`id` = 1 ORDER BY `students`.`id` LIMIT 1;
// в соответствии ссостояниеи model изценитьруководитьвозобновлять
db.First(&student)
db.Model(&student).Where("active = ?", true).Update("name", "jarvis-02")
// UPDATE `students` SET `name`='jarvis-02',`updated_at`='2024-01-11 16:17:39.746' WHERE active = true AND `students`.`deleted_at` IS NULL AND `id` = 1;
Updates
методподдерживать struct
и map[string]interface{}
женьшеньчисло。когдаиспользовать struct
При обновлении по умолчанию GORM Только Уилл возобновлять Нетнулевое значениеполя
//в соответствии с `struct` возобновлятьсвойство,Только Уилл возобновлять Нетнулевое значениеполя
db.First(&student)
db.Model(&student).Updates(Student{Name: "hello", Age: 99, Active: false})
//SELECT * FROM `students` WHERE `students`.`deleted_at` IS NULL AND `students`.`id` = 1 ORDER BY `students`.`id` LIMIT 1;
//в соответствии с `map` возобновлятьсвойство
db.First(&student)
db.Model(&student).Updates(map[string]interface{}{"name": «Губка Боб», "age": 88, "active": false})
//UPDATE `students` SET `active`=false,`age`=88,`name`='Губка Боб Квадратные Штаны',`updated_at`='2024-01-11 16:39:56.28HERE `students`.`deleted_at` IS NULL AND `id` = 1
Уведомление когдапроходить struct При обновлении GORM Будут обновлены только ненулевые поля. еслитыхочу убедитьсяобозначение Полеодеяловозобновлять,тыдолжениспользовать
Select
возобновлятьвыбрано Поле,илииспользоватьmap
для завершения операции обновления
еслитыдуматьхотетьсуществоватьвозобновлятьчасвыбрано、игнорировать некоторые Поле,Вы можете использовать Select
、Omit
// использовать Map руководить Select
// Student's ID is `111`:
db.First(&student)
// Тольковозобновлятьname
db.Model(&student).Select("name").Updates(map[string]interface{}{"name": "jarvis_002", "age": 66, "active": false})
// UPDATE `students` SET `name`='jarvis_002',`updated_at`='2024-01-11 17:10:53.649' WHERE `students`.`deleted_at` IS NULL AND `id` = 1
db.First(&student)
// Все, кроме имени, возобновлено.
db.Model(&student).Omit("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": true})
// UPDATE `students` SET `active`=true,`age`=18,`updated_at`='2024-01-11 17:10:53.654' WHERE `students`.`deleted_at` IS NULL AND `id` = 1;
// использовать Struct руководить Выберите (будет select нулевое значениеполя),нулевое значение Полетакже Уилл возобновлять
// Уведомление userизidНетспособныйдля0
db.First(&student)
db.Model(&student).Select("Name", "Age").Updates(Student{Name: "new_name", Age: 0})
// UPDATE `students` SET `updated_at`='2024-01-11 17:10:53.658',`name`='new_name',`age`=0 WHERE `students`.`deleted_at` IS NULL AND `id` = 1
// Select Местоиметь Поле(Запросвключатьнулевое значение Полеиз Местоиметь Поле)
db.First(&student)
fmt.Println(student)
db.Model(&student).Select("*").Updates(Student{Name: "jarvis_004", Birthday: time.Now(), Age: 33, Active: false, Model: gorm.Model{ID: 3, CreatedAt: time.Now(), UpdatedAt: time.Now()}})
// Select удалять "CreatedAt","birthday"снаружииз Местоиметь Поле(включатьнулевое значение Полеиз Местоиметь Поле),Идентификатор уведомления станет 0
db.Model(&student).Select("*").Omit("CreatedAt", "birthday").Updates(Student{Name: "zhuliang", Age: 0})
Для операций обновления GORM поддерживать BeforeSave
、BeforeUpdate
、AfterSave
、AfterUpdate
крюк, эти методы Волясуществоватьвозобновлять при записи вызываются, подробнее см. крюк
func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
if u.Role == "admin" {
return errors.New("admin user not allowed to update")
}
return
}
// тест
func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
fmt.Println("Изменено")
return
}
еслитыеще нетпроходить Model
обозначение Записыватьизпервичный ключ,но GORM Пакетные обновления будут выполняться
// в соответствии с struct возобновлять--->партиявозобновлять Нетспособный用Hook
db.Model(&student).Where("active = ?", true).Updates(Student{Name: "hello", Age: 18})
// UPDATE `students` SET `updated_at`='2024-01-11 17:28:11.236',`name`='hello',`age`=18 WHERE active = true AND `students`.`deleted_at` IS NULL
// в соответствии с map возобновлять
db.Table("students").Where("id IN ?", []int{1, 2}).Updates(map[string]interface{}{"name": "jiajia_009", "age": 99})
// UPDATE `students` SET `age`=99,`name`='jiajia_009' WHERE id IN (1,2)
еслисуществоватьбезиметьлюбойсостояниеизвыполнить при обстоятельствах ХОРОШОпартиявозобновлять,По умолчанию,GORM не выполняет операцию и возвращает ErrMissingWhereClause
ошибка
В этом отношении,Вам нужно добавить немного состояния,или ВОЗиспользовать Родной SQL или включен AllowGlobalUpdate
режим, например:
db.Model(&User{}).Update("name", "jinzhu").Error //Сообщить об ошибке gorm.ErrMissingWhereClause
db.Model(&User{}).Where("1 = 1").Update("name", "jinzhu") //Может
// UPDATE users SET `name` = "jinzhu" WHERE 1=1
// Способ 1. Непосредственно выполните Роднойsql для глобального возобновления.
db.Exec("UPDATE users SET name = ?", "jinzhu")
// UPDATE users SET name = "jinzhu"
// Способ 2:использоватьsession
db.Session(&gorm.Session{AllowGlobalUpdate: true}).Model(&Student{}).Update("name", "Джарвис_010")
// UPDATE `students` SET `name`='Джарвис_010',`updated_at`='2024-01-11 19:12:42.408' WHERE `students`.`eted_at` IS NULL
Получить количество строк, затронутых обновлением
// проходить `RowsAffected` получатьвозобновлятьиз Записыватьчисло
result := db.Model(User{}).Where("active = ?", true).Updates(User{Name: "hello", Age: 18})
fmt.Println(result.RowsAffected) // возобновлятьиз Записыватьчисло
fmt.Println(result.Error) // ошибка
GORM позволятьиспользовать SQL Выражения обновляют столбцы, например:
// user из ID да `1`
db.First(&student)
db.Model(&student).Update("age", gorm.Expr("age * ? + ?", 2, 100))
// UPDATE `students` SET `age`=age * 2 + 100,`updated_at`='2024-01-11 19:29:40.712' WHERE `students`.`deleted_at` IS NULL
db.First(&student)
db.Model(&student).Updates(map[string]interface{}{"age": gorm.Expr("age - ? + ?", 2, 100)})
// UPDATE `students` SET `age`=age - 2 + 100,`updated_at`='2024-01-11 19:29:40.713' WHERE `students`.`deleted_at` IS NULL
db.First(&student)
db.Model(&student).UpdateColumn("age", gorm.Expr("age - ?", 10))
// UPDATE `students` SET `age`=age - 10 WHERE `students`.`deleted_at` IS NULL
db.First(&student)
db.Model(&student).Where("age > 100").UpdateColumn("age", gorm.Expr("age - ?", 100))
// UPDATE `students` SET `age`=age - 100 WHERE age > 100 AND `students`.`deleted_at` IS NULL
и GORM также позволяет использовать выражения SQL.、пользовательский тип данныхиз Context Valuer для обновления, например:
// в соответствии спользовательский тип данныхсоздавать
type Location struct {
X, Y int
}
func (loc Location) GormValue(ctx context.Context, db *gorm.DB) clause.Expr {
return clause.Expr{
SQL: "ST_PointFromText(?)",
Vars: []interface{}{fmt.Sprintf("POINT(%d %d)", loc.X, loc.Y)},
}
}
db.Model(&User{ID: 1}).Updates(User{
Name: "jinzhu",
Location: Location{X: 100, Y: 100},
})
// UPDATE `user_with_points` SET `name`="jinzhu",`location`=ST_PointFromText("POINT(100 100)") WHERE `id` = 1
использоватьребенок Запросвозобновлятьповерхность
db.Model(&user).Update("company_name", db.Model(&Company{}).Select("name").Where("companies.id = users.company_id"))
// UPDATE "users" SET "company_name" = (SELECT name FROM companies WHERE companies.id = users.company_id);
db.Table("users as u").Where("name = ?", "jinzhu").Update("company_name", db.Table("companies as c").Select("name").Where("c.id = u.company_id"))
//UPDATE users as u SET `company_name`=(SELECT name FROM companies as c WHERE c.id = u.company_id) WHERE name = 'jinzhu'
db.Table("users as u").Where("name = ?", "jinzhu").Updates(map[string]interface{}{"company_name": db.Table("companies as c").Select("name").Where("c.id = u.company_id")})
//UPDATE users as u SET `company_name`=(SELECT name FROM companies as c WHERE c.id = u.company_id) WHERE name = 'jinzhu'
Если вы хотите пропустить обновление Hook
Метод, не отслеживающий время возобновления, можно использовать UpdateColumn
、UpdateColumns
,Его использование аналогично Update
、Updates
// Обновить один столбец
db.Model(&user).UpdateColumn("name", "hello")
// UPDATE users SET name='hello' WHERE id = 111;
// возобновить несколько столбцов
db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18 WHERE id = 111;
// возобновлятьвыбиратьв Список
db.Model(&user).Select("name", "age").UpdateColumns(User{Name: "hello", Age: 0})
// UPDATE users SET name='hello', age=0 WHERE id = 111;
возвращатьсяодеяло Исправлятьизданные,толькоподходящийиспользуется дляподдерживать Returning база данных, например:
// возвращаться Местоиметь Список
var users []User
DB.Model(&users).Clauses(clause.Returning{}).Where("role = ?", "admin").Update("salary", gorm.Expr("salary * ?", 2))
// UPDATE `users` SET `salary`=salary * 2,`updated_at`="2021-10-28 17:37:23.19" WHERE role = "admin" RETURNING *
// users => []User{{ID: 1, Name: "jinzhu", Role: "admin", Salary: 100}, {ID: 2, Name: "jinzhu.2", Role: "admin", Salary: 1000}}
// возвращатьсяобозначениеиз Список
DB.Model(&users).Clauses(clause.Returning{Columns: []clause.Column{{Name: "name"}, {Name: "salary"}}}).Where("role = ?", "admin").Update("salary", gorm.Expr("salary * ?", 2))
// UPDATE `users` SET `salary`=salary * 2,`updated_at`="2021-10-28 17:37:23.19" WHERE role = "admin" RETURNING `name`, `salary`
// users => []User{{ID: 0, Name: "jinzhu", Role: "", Salary: 100}, {ID: 0, Name: "jinzhu.2", Role: "", Salary: 1000}}
GORM предоставил Changed
метод, который можно использовать в Before Update Hook Здесь он вернет логическое значение того, изменилось ли поле.
Changed
Методы можно использовать только с Update
、Updates
метод Вместеиспользовать,иэто Толькодаисследовать Model Значение поля объекта такое же, как Update
、Updates
Равны ли значения, если значение изменилось и поле не было проигнорировано, оно будет возвращено true
func (u *Student) BeforeUpdate(tx *gorm.DB) (err error) {
// если age Полеиметьизменять,не разрешено,Сообщите об ошибке напрямую
if tx.Statement.Changed("age") {
fmt.Println("xx")
return errors.New("age not allowed to change")
}
// если Name Полеиметьизменять,изменить возрастдля18
if tx.Statement.Changed("Name") {
tx.Statement.SetColumn("age", 18)
}
// еслипроизвольный Полеиметьизменять,ИсправлятьCreatedAtчасмежду
if tx.Statement.Changed() {
tx.Statement.SetColumn("CreatedAt", time.Now())
}
return nil
}
//Изменяем имя и изменяем возраст Установить на 18
db.Model(&Student{Model: gorm.Model{ID: 1}, Name: "Джарвис"}).Updates(map[string]interface{}{"name": "Джарвис_001"})
// имя Исправлять,нодаимя其实ибезиметь Изменять,таквозраст Нетвстречаодеяло Исправлять
db.Model(&Student{Model: gorm.Model{ID: 1}, Name: "Джарвис_001"}).Updates(map[string]interface{}{"name": "Джарвис_002"})
//Изменяем имя и изменяем возраст Установить на 18
db.Model(&Student{Model: gorm.Model{ID: 1}, Name: "Джарвис_002"}).Updates(Student{Name: "Джарвис_01"})
//имя Исправлять,нодаимя其实ибезиметь Изменять,таквозраст Нетвстречаодеяло Исправлять
db.Model(&Student{Model: gorm.Model{ID: 1}, Name: "Джарвис_01"}).Updates(Student{Name: "Джарвис_02"})
// Изменение возраста не допускается.
db.Model(&Student{}).Where("id=?", 1).Updates(map[string]interface{}{"age": 100})
//произвольный Полеиметьизменять,возобновлятьCreatedAtчасмежду
db.Model(&Student{}).Where("id=?", 1).Updates(map[string]interface{}{"active": false})
Быть в Before крюксередина改Изменятьхотетьвозобновлятьизценить,еслиэтодаполныйизвозобновлять,Можетиспользовать Save
;нетно,должениспользовать SetColumn
,Например:
func (student *Student) BeforeSave(tx *gorm.DB) (err error) {
if pw, err := bcrypt.GenerateFromPassword(student.Password, 0); err == nil {
tx.Statement.SetColumn("EncryptedPassword", pw)
}
if tx.Statement.Changed("Code") {
student.Age += 20
tx.Statement.SetColumn("Age", student.Age)
}
return nil
}
db.Model(&student).Update("Name", "jinzhu")
db.First(&student)
db.Model(&student).Update("Name", "Джарвис_010")
// Просто возобновить имя, зашифровать имя
func (student *Student) BeforeSave(tx *gorm.DB) (err error) {
if genName, err := bcrypt.GenerateFromPassword([]byte(student.Name), 0); err == nil {
tx.Statement.SetColumn("name", genName)
}
return nil
}
db.First(&student)
db.Model(&student).Where("id=?", 1).Updates(Student{Name: "", Code: 200}) // тольковозобновлять Нетнулевое значение Поле
// UPDATE `students` SET `updated_at`='2024-01-11 20:02:28.633',`code`=200 WHERE id=1 AND `students`.`deleted_at` IS NULL
// можно увидетьNameПоле Нет Уилл возобновлять,Это разумно,потому чтодляеслинулевое значение Полетакжевозобновлять,Многие данные в таблице учеников будут пустыми при возобновлении.
//Модель таблицы изменена на
type Student struct {
gorm.Model
Name sql.NullString
Age uint8
Code int64
}
// Измените выражение на
db.Model(&student).Where("id=?", 1).Updates(Student{Code: 200, Name: sql.NullString{"", true}})
// можно увидеть name Полетакжевозобновлять Понятно,этотдапотому чтодля sql.NullString{"", true} встречаодеялораспознаватьдляда Нетнулевое значение,Итак, Уилл возобновлять
//UPDATE `students` SET `updated_at`='2024-01-11 20:07:10.218',`name`='',`code`=200 WHERE id=1 AND `students`.`deleted_at` IS NULL
// Модель таблицы изменена на
type Student struct {
gorm.Model
Name *string
Age uint8
Code int64
}
// Измените выражение на
db.First(&student)
var empty = ""
db.Model(&student).Updates(Student{Code: 200, Name: &empty}) // тольковозобновлять Нетнулевое значение Поле
// Могу назвать Полевозобновлять Понятно,этотдапотому чтодля name Поледауказательтип,указательтипизнулевое значениеда nil,таквстречаодеялораспознаватьдляда Нетнулевое значение,Итак, Уилл возобновлять
// UPDATE `students` SET `updated_at`='2024-01-11 20:10:56.543',`name`='',`code`=200 WHERE `students`.`deleted_at` IS NULL
Лично я считаю, что в повседневной разработке на Go, если у вас есть сомнения, просто используйте указатели, и в этом нет ничего плохого.
Удалить записьчас,удалитьудалятьобъектнуждатьсяхотетьобозначениепервичный ключ,нетновстречакурок партия Delete,Например:
// student из ID да `1`--->мягкое удаление
db.First(&student)
db.Delete(&student)
// UPDATE `students` SET `deleted_at`='2024-01-11 21:08:14.107' WHERE `students`.`deleted_at` IS NULL
// со лбомснаружисостояниеизудалитьудалять
db.First(&student)
db.Where("id = ?", "1").Delete(&student)
// UPDATE `students` SET `deleted_at`='2024-01-11 21:10:48.182' WHERE id = '1' AND `students`.`deleted_at` IS NULL
GORM разрешено пройтипервичный ключ(Можетдасложныйпервичный ключ)ив соответствиисостояние Приходитьудалитьудалятьобъект,это Можетиспользоватьчисло Характер(Например, следующий примерребенок。также Можетиспользоватьнить——переводить ВОЗПримечание)。Проверять Запрос-в соответствиисостояние(Query Inline Conditions) Узнать больше.
// Сначала вставьте
var student = Student{Name: «Большой-большой волк», Age: 99}
db.Create(&student)
db.Delete(&student, 3)
db.Delete(&student, "10")
db.Delete(&student, []int{0, 1, 2})
Для операций удаления GORM поддерживать BeforeDelete
、AfterDelete
Hook,существоватьудалитьудалятьво время записивстречавызовэтотнекоторыйметод,Проверять Hook Получить подробности
func (s *Student) BeforeDelete(tx *gorm.DB) (err error) {
if s.Role == "admin" {
return errors.New("admin student not allowed to delete")
}
return
}
еслиобозначениеизценить Нетвключатьхозяинсвойство,Так GORM встреча Выполнять ХОРОШОпартияудалитьудалять,это Воляудалитьудалять Местоиметьсоответствоватьиз Записывать
db.Where("name LIKE ?", «%Большой-Большой Волк%»).Delete(&student)
db.Delete(&student, "name LIKE ?", «%Большой-Большой Волк%»)
еслисуществоватьбезиметьлюбойсостояниеизвыполнить при обстоятельствах ХОРОШОпартияудалитьудалять,GORM не выполняет операцию и возвращает ErrMissingWhereClause
ошибка
В этом отношении,Вам нужно добавить немного состояния,или ВОЗиспользовать Родной SQL или включен AllowGlobalUpdate
режим, например:
//db.Delete(&student).Error // gorm.ErrMissingWhereClause
db.Where("1 = 1").Delete(&student)
// DELETE FROM `students` WHERE 1=1
db.Exec("DELETE FROM students")
// DELETE FROM students
db.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&student)
// DELETE FROM students
возвращатьсяодеялоудалитьудалятьизданные,толькоподходящийиспользуется дляподдерживать Returning база данных, например:
// возвращаться Местоиметь Список
var student []Student
db.Clauses(clause.Returning{}).Where("role = ?", "admin").Delete(&student)
// DELETE FROM `students` WHERE role = "admin" RETURNING *
// students => []User{{ID: 1, Name: "jinzhu", Role: "admin", Salary: 100}, {ID: 2, Name: "jinzhu.2", Role: "admin", Salary: 1000}}
// возвращатьсяобозначениеиз Список
db.Clauses(clause.Returning{Columns: []clause.Column{{Name: "name"}, {Name: "salary"}}}).Where("role = ?", "admin").Delete(&student)
// DELETE FROM `students` WHERE role = "admin" RETURNING `name`, `salary`
// students => []User{{ID: 0, Name: "jinzhu", Role: "", Salary: 100}, {ID: 0, Name: "jinzhu.2", Role: "", Salary: 1000}}
Если ваша модель содержит gorm.deletedat
Поле(gorm.Model
Уже включено Понятно Должен Поле),это Воляавтоматически полученомягкое удалениеизспособность!
Модельные звонки с возможностью мягкого удаления Delete
, запись не будет сохранена в базе данных. но GORM встреча Воля DeletedAt
Установите текущее время, иты Нетспособный再проходитьобычноиз Запросметодоказаться Должен Записывать。
// user из ID да `111`
db.Delete(&user)
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
// партияудалитьудалять
db.Where("age = ?", 20).Delete(&User{})
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
// существовать Запросчасвстречапренебрегатьодеяломягкое удалениеиз Записывать
db.Where("age = 20").Find(&user)
// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
Если вы не хотите знакомиться gorm.Model
,Вы также можете включить функцию мягкого удаления следующим образом:
type Student struct {
ID int
Deleted gorm.DeletedAt
Name string
}
Вы можете использовать Unscoped
Найти обратимо удаленные записи
var student []Student
db.Unscoped().Where("name = Джарвис").Find(&student)
fmt.Println(student)
Вы также можете использовать Unscoped
Удалить навсегдасоответствоватьиз Записывать
var student []Student
db.Unscoped().Where("id = 38").Find(&student)
db.Unscoped().Delete(&student)
Воля unix временная метка как delete flag
// go get -u gorm.io/plugin/soft_delete
//db.AutoMigrate(&User2{})
import "gorm.io/plugin/soft_delete"
type User2 struct {
ID uint
Name string
DeletedAt soft_delete.DeletedAt
}
// создавать
var user2 User2=User2{Name: «Одноклассник Сяосинь»}
db.Create(&user2)
// удалитьудалять
db.Delete(&user2)
// Запрос
SELECT * FROM users WHERE deleted_at = 0;
// удалитьудалять
UPDATE users SET deleted_at = /* current unix second */ WHERE ID = 1;
INFO Сотрудничество unique Полеиспользоватьмягкое удалить, когда вам нужноиспользовать это основано на unix с отметкой времени
DeletedAt
Полесоздавать сводный индекс,Например: import "gorm.io/plugin/soft_delete" type User struct { ID uint Name string `gorm:"uniqueIndex:udx_name"` DeletedAt soft_delete.DeletedAt `gorm:"uniqueIndex:udx_name"` }
использовать 1
/ 0
как delete flag
import "gorm.io/plugin/soft_delete"
type User struct {
ID uint
Name string
IsDel soft_delete.DeletedAt `gorm:"softDelete:flag"`
}
// Запрос
SELECT * FROM users WHERE is_del = 0;
// удалитьудалять
UPDATE users SET is_del = 1 WHERE ID = 1;
Родной Запрос SQL и Scan
type User3 struct {
ID int
Name string
Age int
}
// создаватьповерхность
db.AutoMigrate(&User3{})
// вставлятьданные
var student = []User3{
{Name: «Одноклассники Сяо Ай», Age: 12},
{Name: «Одноклассник Сяосинь», Age: 13},
{Name: «Одноклассник Сяобин», Age: 18},
{Name: «Одноклассник Сяофан», Age: 192},
}
db.Create(&student)
for _, user := range student {
fmt.Println(user.ID)
}
var user User3
db.Raw("SELECT id, name, age FROM user3 WHERE name = ?",«Одноклассник Сяосинь»).Scan(&user)
fmt.Println(user)
var age int
db.Raw("SELECT SUM(age) FROM user3 WHERE name like ?", "%Одноклассник Сяосинь%").Scan(&age)
fmt.Println(age)
var users []User3
db.Raw("SELECT * FROM user3 WHERE id > ?", 0).Scan(&users)
fmt.Println(users)
// mysql Нетподдерживать
var users []User3
db.Raw("UPDATE user3 SET name = ? WHERE age = ? RETURNING id, name", «Одноклассник Сяосинь», 12).Scan(&users)
fmt.Println(users)
Exec
Родной SQL
db.Exec("DROP TABLE users")
db.Exec("UPDATE orders SET shipped_at = ? WHERE id IN ?", time.Now(), []int64{1, 2, 3})
// Exec with SQL Expression
db.Exec("UPDATE users SET money = ? WHERE name = ?", gorm.Expr("money * ? + ?", 10000, 1), "jinzhu")
Уведомление GORM Разрешить предварительную компиляцию кэша SQL заявление Приходитьулучшатьпроизводительность,Проверять производительность Получить подробности
GORM поддерживать sql.NamedArg
、map[string]interface{}{}
или struct Именованные параметры формы, например:
// тест
var user []User3
db.Where("name = @name OR age = @age", sql.Named("name", «Одноклассник Сяосинь»), sql.Named("age", "12")).Find(&user)
fmt.Println(user)
var users []User3
db.Where("name = @name OR age = @age", sql.Named("name", «Одноклассник Сяосинь»), sql.Named("age", "12")).Find(&users)
fmt.Println(users)
// То же, что и другие
db.Where("name1 = @name OR name2 = @name", map[string]interface{}{"name": "jinzhu2"}).First(&result3)
// SELECT * FROM `users` WHERE name1 = "jinzhu2" OR name2 = "jinzhu2" ORDER BY `users`.`id` LIMIT 1
// Родной SQL иименованные параметры
db.Raw("SELECT * FROM users WHERE name1 = @name OR name2 = @name2 OR name3 = @name",
sql.Named("name", "jinzhu1"), sql.Named("name2", "jinzhu2")).Find(&user)
// SELECT * FROM users WHERE name1 = "jinzhu1" OR name2 = "jinzhu2" OR name3 = "jinzhu1"
db.Exec("UPDATE users SET name1 = @name, name2 = @name2, name3 = @name",
sql.Named("name", "jinzhunew"), sql.Named("name2", "jinzhunew2"))
// UPDATE users SET name1 = "jinzhunew", name2 = "jinzhunew2", name3 = "jinzhunew"
db.Raw("SELECT * FROM users WHERE (name1 = @name AND name3 = @name) AND name2 = @name2",
map[string]interface{}{"name": "jinzhu", "name2": "jinzhu2"}).Find(&user)
// SELECT * FROM users WHERE (name1 = "jinzhu" AND name3 = "jinzhu") AND name2 = "jinzhu2"
type NamedArgument struct {
Name string
Name2 string
}
db.Raw("SELECT * FROM users WHERE (name1 = @Name AND name3 = @Name) AND name2 = @Name2",
NamedArgument{Name: "jinzhu", Name2: "jinzhu2"}).Find(&user)
// SELECT * FROM users WHERE (name1 = "jinzhu" AND name3 = "jinzhu") AND name2 = "jinzhu2"
Генерировать без выполнения SQL
и其женьшеньчисло,Можетиспользуется для Подготовитьилитестгенерироватьиз SQL, подробности см. по ссылке. Session
var user User3
//session := db.Session(&gorm.Session{DryRun: true})
//session.First(&user, 1)
//fmt.Println(user)
stmt := db.Session(&gorm.Session{DryRun: true}).First(&user, 1).Statement
fmt.Println(stmt.SQL.String()) //=> SELECT * FROM `users` WHERE `id` = $1 ORDER BY `id`
fmt.Println(stmt.Vars) //=> []interface{}{1}
Вернуть сгенерированный SQL
Но не казнён.
GORMиспользовать database/sql заполнители параметров для создания SQL оператор, который автоматически экранирует аргументы, чтобы избежать SQL вводится, но мы не гарантируем создание SQL из Безопасность,Пожалуйста, используйте это только для отладки.
var users []User3
sql := db.ToSQL(func(tx *gorm.DB) *gorm.DB {
return tx.Model(&User3{}).Where("id = ?", 100).Limit(10).Order("age desc").Find(&users)
})
fmt.Println(sql)
//SELECT * FROM `user3` WHERE id = 100 ORDER BY age desc LIMIT 10
Row
& Rows
получать *sql.Row
результат
// использовать GORM API строить SQL
var name string
var age int
row := db.Table("user3").Where("name = ?", "Одноклассник Сяосинь").Select("имя", "age").Row()
row.Scan(&name, &age)
fmt.Println(name)
fmt.Println(age)
// использовать Родной SQL
var name string
var age int
row := db.Raw("select name, age from user3 where name = ?", «Одноклассник Сяосинь»).Row()
row.Scan(&name, &age)
fmt.Println(name)
fmt.Println(age)
получать *sql.Rows
результат
// использовать GORM API строить SQL
var name string
var age int
rows, _ := db.Model(&User3{}).Where("name like ?", "%Xiaoxin%").Select("имя, age").Rows()
defer rows.Close()
for rows.Next() {
rows.Scan(&name, &age)
fmt.Printf("nameда:%s,ageда:%d\n",name,age)
}
// Родной SQL
var name string
var age int
rows, err := db.Raw("select name, age from user3 where name like ?", "%Xiaoxin%").Rows()
defer rows.Close()
for rows.Next() {
rows.Scan(&name, &age)
fmt.Printf("nameда:%s,ageда:%d\n",name,age)
}
Перейти к FindInBatches получатькаксуществоватьпартиясередина Запросииметь дело с Записыватьизинформация, Перейти к Group состояние получатькакстроитьсложный SQL Запросить информацию
sql.Rows
Сканировать в modelиспользовать ScanRows
Воляодин ХОРОШОЗаписывать Сканировать в struct,Например:
rows, err := db.Model(&User3{}).Where("name like ?", "%Xiaoxin%").Select("имя,age").Rows()
defer rows.Close()
var user User3
for rows.Next() {
// ScanRows Воляодин ХОРОШОСканировать в user
db.ScanRows(rows, &user)
fmt.Println(user)
}
Run mutliple SQL in same db tcp connection (not in a transaction)
db.Connection(func(tx *gorm.DB) error {
tx.Exec("SET my.role = ?", "admin")
tx.First(&User{})
})
GORM uses SQL builder generates SQL internally, for each operation, GORM creates a *gorm.Statement
object, all GORM APIs add/change Clause
for the Statement
, at last, GORM generated SQL based on those clauses
For example, when querying with First
, it adds the following clauses to the Statement
clause.Select{Columns: "*"}
clause.From{Tables: clause.CurrentTable}
clause.Limit{Limit: 1}
clause.OrderByColumn{
Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey},
}
Then GORM build finally querying SQL in the Query
callbacks like:
Statement.Build("SELECT", "FROM", "WHERE", "GROUP BY", "ORDER BY", "LIMIT", "FOR")
Which generate SQL:
SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1
You can define your own Clause
and use it with GORM, it needs to implements Interface
Check out examples for reference
For different databases, Clauses may generate different SQL, for example:
db.Offset(10).Limit(5).Find(&users)
// Generated for SQL Server
// SELECT * FROM "users" OFFSET 10 ROW FETCH NEXT 5 ROWS ONLY
// Generated for MySQL
// SELECT * FROM `users` LIMIT 5 OFFSET 10
Which is supported because GORM allows database driver register Clause Builder to replace the default one, take the Limit as example
GORM defined Many Clauses, and some clauses provide advanced options can be used for your application
Although most of them are rarely used, if you find GORM public API can’t match your requirements, may be good to check them out, for example:
db.Clauses(clause.Insert{Modifier: "IGNORE"}).Create(&user)
// INSERT IGNORE INTO users (name,age...) VALUES ("jinzhu",18...);
GORM provides interface StatementModifier allows you modify statement to match your requirements, take Hints as example
import "gorm.io/hints"
db.Clauses(hints.New("hint")).Find(&User{})
// SELECT * /*+ hint */ FROM `users`