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
CreateBulkzamiast metodyCreate, która umożliwia tworzenie wielu jednostek w pojedynczej operacji. - Wywołaj
Createdla 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
Limitdo ustawienia maksymalnej liczby wyników do zwrócenia. - Użyj metody
Offsetdo pominięcia niektórych poprzednich wyników. - Użyj metody
Orderdo 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.