W poprzednim wpisie, dotyczącym EF Core, pokazałem jak utworzyć prostą bazę danych składającą się z jednej tabeli w podejściu Code First. Jednak baza danych do czegoś służy, a nie wegetuje sobie gdzieś. Dzisiaj wykonamy na niej proste operację CRUD, czyli dodamy element (Create), wczytamy go z bazy danych (Read), zmodyfikujemy jego zawartość (Update) oraz usuniemy z bazy danych (Delete). CRUD jest oczywiście akronimem od tych wszystkich operacji.
Do tej pory z cyklu poradników o EF ukazały się:
Przypomnienie
Trochę przypomnienia z poprzedniego wpisu, żebyście nie musieli weryfikować go od nowa. Operujemy na tabeli detektywa, określonego przez klasę:
public class Detective { public int DetectiveId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } }
a nasza baza danych określona jest przez taki DBContext:
class DetectiveDbContext : DbContext { public DbSet<Detective> Detectives { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(@"Server = (localdb)\mssqllocaldb; Database = BlogDetectiveDatabase; Trusted_Connection = True; "); } }
Dzięki temu w bazie danych o nazwie BlogDetectiveDatabase mamy tabelę Detectives.
Dodawanie elementów
Pora dodać do bazy dane. Jako, że projekt jest w aplikacji konsolowej przejdziemy do metody Main i tam stworzymy kod odpowiedzialny za dodanie nowego detektywa do tabeli.
var detective = new Detective() { Age = 25, FirstName = "Julian", LastName = "Kowalski" }; using (var db = new DetectiveDbContext()) { db.Detectives.Add(detective); db.SaveChanges(); }
Tworzymy instancję detektywa z jakimiś wartościami, a następnie dodajemy ją, za pomocą metody Add, do stworzonego przez nas DbSetu, który odzwierciedla odpowiednią tabelę. EF Core sam zajmie się dodaniem instancji do bazy danych, nasza praca na tym się kończy.
Należy jednak pamiętać, żeby dane zostały utrwalone (zapisane na stałe) należy użyć metody SaveChanges. Inaczej można się zdziwić, że dodane rzeczy przepadły. Tak samo jest z aktualizacją oraz usunięciem danych, więc później nie będę już o tym wspominał.
Utworzony kontekst bazy danych został zawarty w using. W skrócie oznacza to, że po opuszczeniu bloku wywoła się metoda Dispose (do zwalniania zasobów zewnetrznych). EF Core bardzo dobrze radzi sobie ze zwalnianiem zasobów i często nie musimy sami wywoływać metody Dispose, czy to przez bezpośrednie wywołanie czy przez wyrażenie using. Jednak taki zapis jest dość częsty, bezpieczniejszy i występuje w dokumentacji MSDN.
Gdy przejdziemy do SQL Server Object Explorer i wczytamy zawartość tabeli Detectives (klikamy na tabelę prawym przyciskiem myszy, po czym wybieramy View Data) zobaczymy dodany obiekt.
A skąd się wzięło Id? Akurat jest to pole klucza głównego (ang. primary key PK), które identyfikuje naszego detektywa, bo przecież na świecie może być kilku Julianów Kowalskich w tym samym wieku. EF Core samo wygeneruje identyfikator i nie musimy tego robić ręcznie. W zasadzie nie dało by się utworzyć obiektu bez PK, jest to pole obowiązkowe w tabeli bazy danych.
Odczytywanie elementów
No dobra możemy odczytać dane z jakiegoś wbudowanego narzędzia w Visual Studio, ale co nam po tym skoro piszemy aplikację. Musimy to zrobić za pomocą kodu:
var db = new DetectiveDbContext(); var detectives = db.Detectives; foreach (var detective in detectives) { Console.WriteLine( $"{detective.FirstName} {detective.LastName}, age: {detective.Age}"); } Console.Read();
Po prostu iterujemy po liście i odczytujemy wartość. Możemy oczywiście zamienić naszą listę na typ IList wywołując ToList() lub co tam innego chcemy. Taki jest rezultat:
W tym przypadku nie użyłem wyrażenia using do stworzenie instancji kontekstu.
Aktualizacja elementu
Wyobraźmy sobie, że odczytaliśmy naszego Juliana i zmieniamy jego wiek, bo właśnie są jego urodziny, więc jest starszy, a my musimy dbać o to by dane w bazie danych były zgodne z rzeczywistością. Uwaga. nie róbcie tego w domu, nie przechowujcie wieku, tylko datę urodzenia. Do tego posłuży nam:
var db = new DetectiveDbContext(); var detective = db.Detectives.FirstOrDefault(d => d.DetectiveId == 1); detective.Age += 100; db.SaveChanges();
Ha, nie musimy nawet używać metody, ponieważ EF Core śledzi obiekt za nas. Ale jakby nie śledził zawsze możemy użyć metody Update.
var detective = new Detective() { DetectiveId = 1, Age = 25, FirstName = "Julian", LastName = "Kowalski" }; var db = new DetectiveDbContext(); detective.Age += 100; db.Detectives.Update(detective); db.SaveChanges();
Coś się Wam nie zgadza, nie wiedzieliście, że w naszej aplikacji czas działa inaczej i dodajemy 100 lat, a nie rok? Uwaga. Gdybym w powyższym przykładzie nie dodał ID do instancji detektywa, to EF nie wiedziałby co ma zmodyfikować.
Usuwanie danych
Pora na ostatnią, zabójcza operację, szczególnie dla naszego Juliana. Julian dożył wieku starczego, ma już 125 lat, dlatego nasz system nie musi przechowywać o nim danych. Czas przejść na zasłużoną emeryturę.
var db = new DetectiveDbContext(); var detective = db.Detectives.FirstOrDefault(d => d.DetectiveId == 1); db.Detectives.Remove(detective); db.SaveChanges();
I po Julianie śladu już nie ma.
Podsumowanie
EF Core pozwala nam na dokonywanie bardziej skomplikowanych operacji niż tylko te wymienione tutaj, zazwyczaj korzystając z LINQ. Proste operację są bardzo intuicyjne (i proste 😛 ), jednak należy pamiętać o kilku elementach, szczególnie, że należy zapisywać stan bazy danych po dokonaniu na nim zmian.