Trudny / egzaminacyjny · lekcja 16

Pełny CRUD z bazą danych w EF Core — lista produktów

Czas połączyć wszystko z poprzedniej lekcji w jeden, kompletny, DZIAŁAJĄCY przykład: pełny CRUD (Create, Read, Update, Delete) na prawdziwej bazie SQLite przez Entity Framework Core, z walidacją danych przez Data Annotations. To najbardziej praktyczny, powtarz...

Zacznij tutaj

Po co się tego uczymy?

Czas połączyć wszystko z poprzedniej lekcji w jeden, kompletny, DZIAŁAJĄCY przykład: pełny CRUD (Create, Read, Update, Delete) na prawdziwej bazie SQLite przez Entity Framework Core, z walidacją danych przez Data Annotations. To najbardziej praktyczny, powtarzalny wzorzec w całym tym dziale — niemal każda funkcjonalność aplikacji webowej (produkty, zamówienia, kontakty, wpisy na blogu) sprowadza się do tego samego szablonu operacji.

Wprowadzenie

Teoria

Cztery operacje CRUD w Razor Pages z EF Core — każda jako osobna strona:

OperacjaStronaKluczowa metoda EF Core
Create (utwórz)Dodaj.cshtmlcontext.Produkty.Add(nowy) + SaveChangesAsync()
Read (odczytaj)Lista.cshtml, Szczegoly.cshtmlToListAsync(), FindAsync(id)
Update (zaktualizuj)Edytuj.cshtmlFindAsync(id) → zmiana właściwości → SaveChangesAsync()
Delete (usuń)Usun.cshtmlcontext.Produkty.Remove(produkt) + SaveChangesAsync()

Wzorzec strony edycji — częsta pułapka. Strona edycji ma DWIE metody: OnGetAsync(int id) (wczytuje ISTNIEJĄCY produkt z bazy przez FindAsync(id) i wypełnia nim formularz) oraz OnPostAsync() (odbiera ZMIENIONE dane z formularza, ale musi PONOWNIE pobrać oryginalny obiekt z bazy przez jego Id, ręcznie przepisać do niego nowe wartości pól, i dopiero wtedy wywołać SaveChangesAsync()) — NIE wystarczy po prostu podstawić cały nowy obiekt z formularza w miejsce znalezionego, bo EF Core śledzi KONKRETNĄ instancję obiektu pobraną z bazy.

Strona usuwania z potwierdzeniem. Dobra praktyka UX: usuwanie NIGDY nie powinno wykonywać się od razu po kliknięciu linku (żądanie GET) — zawsze przez osobne żądanie POST z formularza z potwierdzeniem ("Czy na pewno chcesz usunąć?"), żeby przypadkowe kliknięcie linku (albo np. robot wyszukiwarki podążający za wszystkimi linkami na stronie) nie skasowało danych.

Wzorzec pobrania z obsługą "nie znaleziono". var produkt = await context.Produkty.FindAsync(id); if (produkt is null) { return NotFound(); } — ZAWSZE sprawdzaj, czy FindAsync faktycznie coś zwrócił, zanim spróbujesz odczytać jego właściwości; użytkownik mógł wpisać w adresie URL nieistniejące Id (np. /Produkty/Edytuj/9999).

Zobacz zależności

Schemat

Lista.cshtml (READ)                    Dodaj.cshtml (CREATE)
GET → ToListAsync()                    GET → pusty formularz
                                        POST → walidacja → Add() → SaveChangesAsync()
        │                                       │
        ▼                                       ▼
     link "Edytuj"                          RedirectToPage("Lista")
        │
        ▼
Edytuj.cshtml (UPDATE)                  Usun.cshtml (DELETE)
GET(id) → FindAsync(id) → wypełnij      GET(id) → FindAsync(id) → pokaż potwierdzenie
          formularz istniejącymi         POST(id) → FindAsync(id) → Remove() →
          danymi                                    SaveChangesAsync()
POST → FindAsync(id) → przepisz                     │
       nowe wartości pól →                          ▼
       SaveChangesAsync()                       RedirectToPage("Lista")
        │
        ▼
   RedirectToPage("Lista")

Połącz z praktyką

Przykład z życia

Panel zarządzania produktami w sklepie internetowym — dokładnie ten zestaw czterech stron (lista, dodaj, edytuj, usuń) to jeden z najczęściej powtarzających się szablonów w praktyce zawodowej programisty webowego, niezależnie od tego, czy zarządza się produktami, klientami, zamówieniami czy artykułami na blogu.