1. Wprowadzenie do operacji na jednostkach w ent
Ten samouczek wyczerpująco przeprowadzi cię przez opanowanie operacji na jednostkach w frameworku ent
, obejmując cały proces tworzenia, wyszukiwania, aktualizacji i usuwania jednostek. Jest odpowiedni dla początkujących, aby stopniowo zagłębić się w podstawową funkcjonalność ent
.
3. Operacja tworzenia jednostki
3.1 Tworzenie pojedynczej jednostki
Tworzenie jednostki jest podstawową operacją dotyczącą trwałości danych. Poniżej znajdują się kroki tworzenia pojedynczego obiektu jednostki przy użyciu frameworku ent
i zapisania go do bazy danych:
- Najpierw zdefiniuj strukturę i pola jednostki, czyli zdefiniuj model jednostki w pliku
schema
. - Uruchom polecenie
ent generate
, aby wygenerować odpowiadający kod operacji na jednostkach. - Użyj wygenerowanej metody
Create
, aby utworzyć nową jednostkę i ustawiaj wartości pól jednostki za pomocą łańcuchowych wywołań. - Na koniec wywołaj metodę
Save
, aby zapisać jednostkę w bazie danych.
Poniżej znajduje się przykład, który demonstruje, jak utworzyć i zapisać jednostkę użytkownika:
package main
import (
"context"
"log"
"entdemo/ent"
)
func main() {
// Utwórz instancję klienta do interakcji z bazą danych
client, err := ent.Open("sqlite3", "plik:ent?mode=pamięć&cache=współdzielona&_fk=1")
if err != nil {
log.Fatalf("Nie udało się otworzyć połączenia z bazą danych: %v", err)
}
defer client.Close()
// Utwórz kontekst
ctx := context.Background()
// Utwórz jednostkę użytkownika za pomocą klienta
a8m, err := client.User.
Create().
SetName("a8m").
Save(ctx)
if err != nil {
log.Fatalf("Nie udało się utworzyć jednostki użytkownika: %v", err)
}
// Jednostka pomyślnie zapisana w bazie danych
log.Printf("Jednostka użytkownika została zapisana: %v", a8m)
}
W tym przykładzie najpierw utworzono klienta bazy danych client
. Następnie, metoda User.Create
jest używana do ustawienia atrybutów nowego użytkownika, a na końcu wywoływana jest metoda Save
, aby zapisać użytkownika w bazie danych.
3.2 Tworzenie jednostek wsadowo
W pewnych sytuacjach może pojawić się potrzeba tworzenia wielu jednostek, na przykład podczas inicjalizacji bazy danych lub operacji importu danych wsadowego. Framework ent
umożliwia tworzenie jednostek wsadowo, co oferuje lepszą wydajność w porównaniu z tworzeniem i zapisywaniem jednostek indywidualnie.
Kroki tworzenia jednostek wsadowo są następujące:
- Użyj metody
CreateBulk
zamiast metodyCreate
, która umożliwia tworzenie wielu jednostek w pojedynczej operacji. - Wywołaj
Create
dla każdej jednostki do utworzenia. - Po utworzeniu wszystkich jednostek, użyj metody
Save
, aby zapisać jednostki w bazie danych wsadowo.
Poniżej znajduje się przykład tworzenia jednostek wsadowo:
package main
import (
"context"
"log"
"entdemo/ent"
)
func main() {
client, err := ent.Open("sqlite3", "plik:ent?mode=pamięć&cache=współdzielona&_fk=1")
if err != nil {
log.Fatalf("Nie udało się otworzyć połączenia z bazą danych: %v", err)
}
defer client.Close()
ctx := context.Background()
// Tworzenie jednostek Pet wsadowo
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("Nie udało się wsadowo utworzyć jednostek Pet: %v", err)
}
log.Printf("Utworzono %d jednostek Pet wsadowo\n", len(pets))
}
W tym przykładzie najpierw utworzono klienta client
, a następnie utworzono wiele jednostek Pet
za pomocą metody CreateBulk
, ustawiając ich nazwy i właściciela. Wszystkie jednostki są zapisywane w bazie danych jednocześnie, gdy wywoływana jest metoda Save
, co zapewnia lepszą wydajność w obsłudze dużej ilości danych.
4. Operacje wyszukiwania jednostek
4.1 Podstawowe zapytania
Zapytania do bazy danych są podstawowym sposobem pobierania informacji. W ent
metoda Query
jest używana do rozpoczęcia zapytania. Poniżej znajdują się kroki i przykład podstawowego zapytania dotyczącego encji:
- Upewnij się, że masz użyteczną instancję
Client
. - Użyj
Client.Query()
lub metod pomocniczych encji, takich jakPet.Query()
do utworzenia zapytania. - Dodaj warunki filtrowania, jeśli są potrzebne, takie jak
Where
. - Wykonaj zapytanie i pobierz wyniki, wywołując metodę
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("Nie udało się otworzyć połączenia z bazą danych: %v", err)
}
defer client.Close()
ctx := context.Background()
// Zapytaj o wszystkich użytkowników o nazwie "a8m"
users, err := client.User.
Query().
Where(user.NameEQ("a8m")).
All(ctx)
if err != nil {
log.Fatalf("Nie udało się zapytać użytkowników: %v", err)
}
for _, u := range users {
log.Printf("Znaleziono użytkownika: %#v\n", u)
}
}
Ten przykład demonstruje, jak znaleźć wszystkich użytkowników o nazwie "a8m".
4.2 Paginacja i Sortowanie
Paginacja i sortowanie to powszechne zaawansowane funkcje podczas zapytań, używane do kontroli kolejności wyników i ilości danych. Oto jak osiągnąć zapytania paginacji i sortowania za pomocą ent
:
- Użyj metody
Limit
do ustawienia maksymalnej liczby wyników do zwrócenia. - Użyj metody
Offset
do pominięcia niektórych poprzednich wyników. - Użyj metody
Order
do określenia pola sortowania i kierunku.
Oto przykład zapytania paginacji i sortowania:
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("Nie udało się otworzyć połączenia z bazą danych: %v", err)
}
defer client.Close()
ctx := context.Background()
// Zapytaj o zwierzęta w malejącej kolejności wieku z paginacją
pets, err := client.Pet.
Query().
Order(ent.Desc(pet.FieldAge)).
Limit(10).
Offset(0).
All(ctx)
if err != nil {
log.Fatalf("Nie udało się zapytać zwierząt: %v", err)
}
for _, p := range pets {
log.Printf("Znaleziono zwierzę: %#v\n", p)
}
}
Ten przykład demonstruje, jak pobrać pierwszą stronę, do 10 rekordów, zwierząt posortowanych malejąco według wieku. Poprzez modyfikację wartości Limit
i Offset
, można osiągnąć przeglądanie danych przez cały zbiór.
5. Operacje aktualizacji encji
5.1 Aktualizacja pojedynczej encji
W wielu aplikacjach aktualizacja encji jest istotną częścią codziennych operacji. W tej sekcji pokażemy, jak użyć frameworka Ent do aktualizacji pojedynczej encji w bazie danych.
Załóżmy, że chcemy zaktualizować wiek użytkownika, możemy skorzystać z metody Update
generowanej przez Ent.
// Zakładając, że mamy już encję użytkownika 'a8m' i kontekst 'ctx'
a8m, err := a8m.Update(). // Utwórz generator aktualizacji użytkownika
SetAge(30). // Ustaw wiek użytkownika na 30 lat
Save(ctx) // Wykonaj operację zapisu i zwróć wynik
if err != nil {
log.Fatalf("Nie udało się zaktualizować użytkownika: %v", err)
}
Można również aktualizować wiele pól jednocześnie:
a8m, err := a8m.Update().
SetAge(30). // Zaktualizuj wiek
SetName("Ariel"). // Zaktualizuj nazwę
AddRank(10). // Zwiększ rangę o 10
Save(ctx)
if err != nil {
log.Fatalf("Nie udało się zaktualizować użytkownika: %v", err)
}
Operację aktualizacji można łańcuchować, co jest bardzo elastyczne i łatwe do odczytu. Wywołanie metody Save
spowoduje wykonanie aktualizacji i zwrócenie zaktualizowanej encji lub komunikatu o błędzie.
5.2 Aktualizacje Warunkowe
Ent pozwala na wykonywanie aktualizacji na podstawie warunków. Oto przykład, w którym aktualizowane będą tylko użytkownicy, którzy spełniają określone warunki.
// Zakładając, że mamy `id` użytkownika i chcemy oznaczyć tego użytkownika jako zakończonego dla wersji `currentVersion`
err := client.Todo.
UpdateOneID(id). // Tworzymy konstruktor aktualizacji według identyfikatora użytkownika
SetStatus(todo.StatusDone).
AddVersion(1).
Where(
todo.Version(currentVersion), // Operacja aktualizacji jest wykonywana tylko, gdy bieżąca wersja pasuje
).
Exec(ctx)
switch {
case ent.IsNotFound(err):
fmt.Println("Zadanie nie znalezione")
case err != nil:
fmt.Println("Błąd aktualizacji:", err)
}
Podczas korzystania z aktualizacji warunkowych, konieczne jest użycie metody .Where()
. Umożliwia to określenie, czy aktualizacja powinna być wykonana na podstawie bieżących wartości w bazie danych, co jest kluczowe dla zapewnienia spójności i integralności danych.
6. Operacje Usuwania Elementów
6.1 Usuwanie Jednego Elementu
Usuwanie elementów to kolejna istotna funkcja w operacjach na bazie danych. Framework Ent udostępnia prosty interfejs API do wykonywania operacji usuwania.
Poniższy przykład pokazuje, jak usunąć podanego użytkownika:
err := client.User.
DeleteOne(a8m). // Tworzymy konstruktor usuwania użytkownika
Exec(ctx) // Wykonujemy operację usuwania
if err != nil {
log.Fatalf("Nie udało się usunąć użytkownika: %v", err)
}
6.2 Usuwanie Warunkowe
Podobnie jak w operacjach aktualizacji, możemy również wykonywać operacje usuwania na podstawie określonych warunków. W pewnych scenariuszach chcemy być w stanie usunąć tylko elementy spełniające określone warunki. Używając metody .Where()
możemy zdefiniować te warunki:
// Załóżmy, że chcemy usunąć wszystkie pliki z datą aktualizacji wcześniejszą niż zadana data
affected, err := client.File.
Delete().
Where(file.UpdatedAtLT(date)). // Wykonujemy usuwanie tylko jeśli czas aktualizacji pliku jest wcześniejszy niż podana data
Exec(ctx)
if err != nil {
log.Fatalf("Nie udało się usunąć plików: %v", err)
}
// Ta operacja zwraca liczbę rekordów dotkniętych operacją usuwania
fmt.Printf("%d plików zostało usuniętych\n", affected)
Wykorzystanie operacji usunięcia warunkowego zapewnia precyzyjną kontrolę nad operacjami na danych, upewniając się, że zostaną usunięte tylko elementy, które rzeczywiście spełniają warunki. Wzmocni to bezpieczeństwo i niezawodność operacji na bazie danych.