1. Введение в операции сущностей ent
Этот учебник позволит вам полностью освоить операции сущностями в рамках ent
фреймворка, охватывая полный процесс создания, запроса, обновления и удаления сущностей. Он подходит для начинающих, позволяя погружаться в основные функции ent
.
3. Операция создания сущности
3.1 Создание одной сущности
Создание сущности является основной операцией для сохранения данных. Ниже приведены шаги по созданию отдельного объекта сущности с использованием фреймворка ent
и сохранению его в базе данных:
- Сначала определите структуру и поля сущности, то есть определите модель сущности в файле
schema
. - Запустите команду
ent generate
, чтобы сгенерировать соответствующий код операции сущности. - Используйте сгенерированный метод
Create
, чтобы создать новую сущность и установить значения полей сущности через цепные вызовы. - Наконец, вызовите метод
Save
для сохранения сущности в базе данных.
Вот пример, демонстрирующий создание и сохранение сущности пользователя:
package main
import (
"context"
"log"
"entdemo/ent"
)
func main() {
// Создание экземпляра Client для взаимодействия с базой данных
client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
if err != nil {
log.Fatalf("Не удалось открыть соединение с базой данных: %v", err)
}
defer client.Close()
// Создание контекста
ctx := context.Background()
// Создание сущности пользователя с помощью Client
a8m, err := client.User.
Create().
SetName("a8m").
Save(ctx)
if err != nil {
log.Fatalf("Не удалось создать сущность пользователя: %v", err)
}
// Сущность успешно сохранена в базе данных
log.Printf("Сущность пользователя сохранена: %v", a8m)
}
В этом примере сначала создается клиент базы данных client
. Затем используется метод User.Create
для установки атрибутов нового пользователя, и, наконец, вызывается метод Save
для сохранения пользователя в базе данных.
3.2 Пакетное создание сущностей
В некоторых сценариях может возникнуть необходимость создавать несколько сущностей, например, при инициализации базы данных или операциях по массовому импорту данных. Фреймворк ent
предоставляет возможность создания сущностей пакетно, что обеспечивает лучшую производительность по сравнению с созданием и сохранением сущностей по отдельности.
Шаги пакетного создания сущностей следующие:
- Используйте метод
CreateBulk
вместо методаCreate
, который позволяет создавать несколько сущностей в одной операции. - Вызовите
Create
для каждой создаваемой сущности. - После создания всех сущностей используйте метод
Save
, чтобы пакетно сохранить сущности в базе данных.
Ниже приведен пример пакетного создания сущностей:
package main
import (
"context"
"log"
"entdemo/ent"
)
func main() {
client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
if err != nil {
log.Fatalf("Не удалось открыть соединение с базой данных: %v", err)
}
defer client.Close()
ctx := context.Background()
// Пакетное создание сущностей Pet
pets, err := client.Pet.CreateBulk(
client.Pet.Create().SetName("pedro").SetOwner(a8m),
client.Pet.Create().SetName("xabi").SetOwner(a8m),
client.Pet.Create().SetName("layla").SetOwner(a8m),
).Save(ctx)
if err != nil {
log.Fatalf("Не удалось пакетно создать сущности Pet: %v", err)
}
log.Printf("Создано %d сущностей Pet пакетно\n", len(pets))
}
В этом примере сначала создается client
, затем множество сущностей Pet
создается с использованием метода CreateBulk
, устанавливая их имена и поля владельца. Все сущности сохраняются в базе данных одновременно при вызове Save
, обеспечивая лучшую производительность для обработки больших объемов данных.
4. Операции запроса сущностей
4.1 Основной запрос
Запрос к базе данных - это основной способ получения информации. В ent
для запуска запроса используется метод Query
. Ниже приведены шаги и пример основного запроса сущностей:
- Убедитесь, что у вас есть экземпляр
Client
, который можно использовать. - Используйте
Client.Query()
или вспомогательные методы сущностей, например,Pet.Query()
, чтобы создать запрос. - Добавьте условия фильтрации, если это необходимо, например, с помощью
Where
. - Выполните запрос и получите результаты, вызвав метод
All
.
package main
import (
"context"
"log"
"entdemo/ent"
"entdemo/ent/user"
)
func main() {
client, err := ent.Open("sqlite3", "file:ent?cache=shared&_fk=1")
if err != nil {
log.Fatalf("Не удалось открыть соединение с базой данных: %v", err)
}
defer client.Close()
ctx := context.Background()
// Запрос всех пользователей с именем "a8m"
users, err := client.User.
Query().
Where(user.NameEQ("a8m")).
All(ctx)
if err != nil {
log.Fatalf("Не удалось выполнить запрос пользователей: %v", err)
}
for _, u := range users {
log.Printf("Найден пользователь: %#v\n", u)
}
}
В этом примере демонстрируется, как найти всех пользователей с именем "a8m".
4.2 Пагинация и сортировка
Пагинация и сортировка - это распространенные расширенные функции при выполнении запросов, используемые для управления порядком вывода и количеством данных. Вот как выполнить запросы с пагинацией и сортировкой с помощью ent
:
- Используйте метод
Limit
, чтобы установить максимальное количество возвращаемых результатов. - Используйте метод
Offset
, чтобы пропустить некоторые предыдущие результаты. - Используйте метод
Order
, чтобы указать поле сортировки и направление.
Вот пример запроса с пагинацией и сортировкой:
package main
import (
"context"
"log"
"entdemo/ent"
"entdemo/ent/pet"
)
func main() {
client, err := ent.Open("sqlite3", "file:ent?cache=shared&_fk=1")
if err != nil {
log.Fatalf("Не удалось открыть соединение с базой данных: %v", err)
}
defer client.Close()
ctx := context.Background()
// Запрос питомцев в порядке убывания возраста с пагинацией
pets, err := client.Pet.
Query().
Order(ent.Desc(pet.FieldAge)).
Limit(10).
Offset(0).
All(ctx)
if err != nil {
log.Fatalf("Не удалось выполнить запрос питомцев: %v", err)
}
for _, p := range pets {
log.Printf("Найден питомец: %#v\n", p)
}
}
В этом примере показано, как получить первую страницу, до 10 записей, питомцев, отсортированных по убыванию возраста. Изменяя значения Limit
и Offset
, можно осуществить пагинацию по всему набору данных.
5. Операции обновления сущностей
5.1 Обновление одной сущности
Во многих приложениях обновление сущностей является важной частью повседневных операций. В этом разделе мы продемонстрируем, как использовать фреймворк Ent для обновления одной сущности в базе данных.
Во-первых, предположим, что нам нужно обновить возраст пользователя. Мы можем использовать сгенерированный Ent метод Update
.
// Предположим, что у нас уже есть сущность пользователя 'a8m' и контекст 'ctx'
a8m, err := a8m.Update(). // Создать построитель обновления пользователя
SetAge(30). // Установить возраст пользователя на 30 лет
Save(ctx) // Выполнить операцию сохранения и вернуть результат
if err != nil {
log.Fatalf("Не удалось обновить пользователя: %v", err)
}
Вы также можете одновременно обновить несколько полей:
a8m, err := a8m.Update().
SetAge(30). // Обновить возраст
SetName("Ariel"). // Обновить имя
AddRank(10). // Увеличить ранг на 10
Save(ctx)
if err != nil {
log.Fatalf("Не удалось обновить пользователя: %v", err)
}
Операцию обновления можно цеплять, что очень гибко и удобно для чтения. Вызов метода Save
выполнит обновление и вернет обновленную сущность или сообщение об ошибке.
5.2 Условные обновления
Ent позволяет выполнять обновления на основе условий. Вот пример, когда будут обновлены только пользователи, соответствующие определенным условиям.
// Предположим, у нас есть `id` пользователя, которого мы хотим пометить как завершенного для версии `currentVersion`
err := client.Todo.
UpdateOneID(id). // Создаем конструктор для обновления по ID пользователя
SetStatus(todo.StatusDone).
AddVersion(1).
Where(
todo.Version(currentVersion), // Операция обновления выполняется только при совпадении текущей версии
).
Exec(ctx)
switch {
case ent.IsNotFound(err):
fmt.Println("Задача не найдена")
case err != nil:
fmt.Println("Ошибка обновления:", err)
}
При использовании условных обновлений необходимо использовать метод .Where()
. Это позволяет определить, должно ли обновление выполняться на основе текущих значений в базе данных, что критически важно для обеспечения согласованности и целостности данных.
6. Операции удаления сущностей
6.1 Удаление одной сущности
Удаление сущностей является еще одной важной функцией в операциях базы данных. Фреймворк Ent предоставляет простой API для выполнения операций удаления.
Следующий пример демонстрирует, как удалить данную сущность пользователя:
err := client.User.
DeleteOne(a8m). // Создаем конструктор для удаления пользователя
Exec(ctx) // Выполняем операцию удаления
if err != nil {
log.Fatalf("Не удалось удалить пользователя: %v", err)
}
6.2 Условное удаление
Аналогично операциям обновления, мы также можем выполнять операции удаления на основе определенных условий. В определенных сценариях мы можем хотеть удалить только сущности, соответствующие определенным условиям. Использование метода .Where()
позволяет определить эти условия:
// Предположим, что мы хотим удалить все файлы с временем обновления раньше определенной даты
affected, err := client.File.
Delete().
Where(file.UpdatedAtLT(date)). // Выполняем удаление только в случае, если время обновления файла раньше указанной даты
Exec(ctx)
if err != nil {
log.Fatalf("Не удалось удалить файлы: %v", err)
}
// Эта операция возвращает количество записей, затронутых операцией удаления
fmt.Printf("%d файлов было удалено\n", affected)
Использование условных операций удаления обеспечивает точный контроль над нашими операциями с данными, гарантируя, что удаляются только сущности, действительно соответствующие условиям. Это улучшает безопасность и надежность операций базы данных.