Trudny / egzaminacyjny · lekcja 24
Projekt 5: Mini portal społecznościowy — wpisy, komentarze i polubienia
Kolejna nazwana wprost w podstawie programowej (INF.04.7.3) funkcjonalność — portal społecznościowy. Ten projekt buduje uproszczony "feed" (strumień wpisów) z możliwością komentowania i polubień, wymagający zalogowania — dobre ćwiczenie z relacji WIELE-do-WIEL...
Zacznij tutaj
Po co się tego uczymy?
Wprowadzenie
Teoria
Wymagania projektu:
- Feed — lista wpisów (tekst + opcjonalnie zdjęcie, upload plików z lekcji 18) od WSZYSTKICH użytkowników, posortowana od najnowszego;
- Dodawanie własnego wpisu — WYMAGA zalogowania (ASP.NET Core Identity, lekcja 14);
- Komentarze pod każdym wpisem — relacja jeden-do-wielu (jeden wpis, wiele komentarzy);
- Polubienia — relacja WIELE-do-WIELU (jeden użytkownik może polubić wiele wpisów, jeden wpis może być polubiony przez wielu użytkowników) — z licznikiem i wizualnym oznaczeniem, czy AKTUALNIE zalogowany użytkownik już polubił dany wpis.
Relacja wiele-do-wielu — tabela pośrednicząca. W przeciwieństwie do relacji jeden-do-wielu z lekcji 17 (klucz obcy bezpośrednio w "słabszej" tabeli), relacja wiele-do-wielu wymaga OSOBNEJ tabeli pośredniczącej: Polubienie (WpisId, UzytkownikId) — każdy wiersz tej tabeli reprezentuje JEDNO polubienie KONKRETNEGO wpisu PRZEZ konkretnego użytkownika. Sprawdzenie "czy zalogowany użytkownik już polubił ten wpis" to zapytanie: context.Polubienia.AnyAsync(p => p.WpisId == wpisId && p.UzytkownikId == idAktualnegoUzytkownika).
Model danych:
public class Wpis { public int Id; public string Tresc; public string? SciezkaZdjecia;
public DateTime DataUtworzenia; public string AutorId;
public List<Komentarz> Komentarze; public List<Polubienie> Polubienia; }
public class Komentarz { public int Id; public string Tresc; public int WpisId;
public string AutorId; public DateTime DataUtworzenia; }
public class Polubienie { public int Id; public int WpisId; public string UzytkownikId; }
Pobieranie wpisów z LICZBĄ polubień i statusem "czy JA polubiłem". Zamiast dociągać CAŁĄ listę polubień dla każdego wpisu (co byłoby marnotrawstwem — potrzebujemy tylko liczby i jednego boola), backend może zwrócić OSOBNY, "spłaszczony" obiekt DTO (Data Transfer Object) zamiast surowego modelu EF Core: WpisDto { Id, Tresc, LiczbaPolubien, CzyJaPolubilem } — kontroler sam oblicza te wartości przez LINQ (.Count(), .Any()) PRZED wysłaniem odpowiedzi, zamiast przesyłać surowe dane i każąc Angularowi je przeliczać.
Zobacz zależności
Schemat
Wpis (1) ──── (N) Komentarz Wpis (N) ──── (N) Uzytkownik
"Dzisiaj super pogoda!" "Super!" - Ala przez tabelę pośredniczącą:
"Zgadzam się" - Bartek Polubienie (WpisId, UzytkownikId)
GET /api/wpisy (wymaga [Authorize], żeby wiedzieć KTO pyta - CzyJaPolubilem)
│
▼
ASP.NET Core:
context.Wpisy
.Select(w => new WpisDto {
Id = w.Id, Tresc = w.Tresc,
LiczbaPolubien = w.Polubienia.Count(),
CzyJaPolubilem = w.Polubienia.Any(p => p.UzytkownikId == idAktualnegoUzytkownika)
})
│
▼
Angular: FeedComponent
@for (wpis of wpisy; track wpis.id) {
<app-wpis-karta [wpis]="wpis" (polubiono)="przelacz(wpis.id)">
}
Połącz z praktyką
Przykład z życia
Facebook, Instagram, LinkedIn — wszystkie duże portale społecznościowe opierają się na tym samym fundamencie: wpisy, komentarze, polubienia (relacja wiele-do-wielu między użytkownikami a treścią) i personalizacja widoku pod KONKRETNEGO zalogowanego użytkownika. Ten projekt buduje maleńką, ale strukturalnie prawdziwą wersję tego mechanizmu.