Entity Framework Core — DbContext, migracje i CRUD od podstaw
Entity Framework Core (EF Core) to ORM (Object-Relational Mapper) — zamiast pisać ręczny SQL, operujesz na obiektach C#, a EF Core sam generuje zapytania. To inny wybór niż Dapper (mikro-ORM, gdzie SQL piszesz ręcznie) — EF Core robi więcej za Ciebie kosztem mniejszej kontroli nad dokładnym zapytaniem.
Instalacja pakietów
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.DesignEncja — zwykła klasa C#
public class Produkt
{
public int Id { get; set; }
public string Nazwa { get; set; } = string.Empty;
public decimal Cena { get; set; }
}Żadnych atrybutów, żadnego dziedziczenia z klasy bazowej — EF Core konwencjonalnie rozpoznaje Id jako klucz główny.
DbContext — most między klasami a bazą danych
public class SklepDbContext : DbContext
{
public DbSet<Produkt> Produkty { get; set; } = null!;
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite("Data Source=sklep.db");
}DbSet<Produkt> reprezentuje tabelę Produkty w bazie danych — każdy wiersz to jeden obiekt Produkt. DbContext śledzi zmiany na tych obiektach i tłumaczy je na SQL, gdy wywołasz SaveChanges().
Migracje — baza danych generowana z modelu C#
dotnet ef migrations add InitialCreate
dotnet ef database updatePierwsza komenda analizuje klasy DbSet w Twoim DbContext i generuje plik migracji z metodami Up() (co zrobić, żeby dojść do tego stanu bazy) i Down() (jak to cofnąć):
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Produkty",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Nazwa = table.Column<string>(nullable: false),
Cena = table.Column<decimal>(nullable: false)
},
constraints: table => table.PrimaryKey("PK_Produkty", x => x.Id));
}
protected override void Down(MigrationBuilder migrationBuilder)
=> migrationBuilder.DropTable(name: "Produkty");
}Druga komenda (dotnet ef database update) faktycznie wykonuje ten SQL na bazie danych. Każda kolejna zmiana modelu (nowa właściwość, nowa klasa) to kolejna migracja — historia zmian struktury bazy danych żyje w kodzie, obok reszty projektu.
CRUD — Create
using var db = new SklepDbContext();
db.Produkty.Add(new Produkt { Nazwa = "Klawiatura", Cena = 149.99m });
db.SaveChanges();Add tylko oznacza obiekt jako “do wstawienia” — żaden SQL nie wykonuje się, dopóki nie wywołasz SaveChanges().
CRUD — Read
var wszystkie = db.Produkty.ToList();
var jeden = db.Produkty.Find(1);
var drogie = db.Produkty.Where(p => p.Cena > 100).ToList();Find szuka po kluczu głównym (najpierw sprawdza pamięć podręczną DbContext, potem bazę danych). Where z LINQ tłumaczy się na WHERE w SQL.
CRUD — Update
var produkt = db.Produkty.Find(1);
produkt.Cena = 129.99m;
db.SaveChanges();Żadnego jawnego Update(). EF Core śledzi zmiany na obiektach pobranych z bazy (change tracking) — wystarczy zmienić właściwość, a SaveChanges() sam wygeneruje odpowiedni UPDATE. To kluczowa różnica względem Dappera, gdzie musisz ręcznie napisać zapytanie UPDATE z każdą kolumną do zmiany.
CRUD — Delete
var produkt = db.Produkty.Find(1);
db.Produkty.Remove(produkt);
db.SaveChanges();Kiedy EF Core, kiedy Dapper
EF Core sprawdza się, gdy chcesz szybko modelować dane jako obiekty i nie potrzebujesz mikrozarządzania każdym zapytaniem — zmiana modelu to migracja, nie ręczne pisanie ALTER TABLE. Dapper sprawdza się, gdy zależy Ci na maksymalnej kontroli nad dokładnym SQL-em (złożone raporty, zoptymalizowane zapytania) i akceptujesz, że migracje i change tracking piszesz sam. Wielu projektów .NET używa obu naraz: EF Core do standardowego CRUD-u, Dapper do wydajnościowo krytycznych zapytań raportowych.
Co dalej
Po opanowaniu podstaw zobacz, jak testować kod korzystający z EF Core w Testowanie EF Core — InMemory vs SQLite, i jak EF Core wpisuje się w szerszą architekturę aplikacji w Clean Architecture (gdzie DbContext żyje w warstwie Infrastructure, za interfejsem repozytorium).
Podsumowanie
Entity Framework Core to encje (zwykłe klasy C#), DbContext z właściwościami DbSet<T> reprezentującymi tabele, migracje generujące i aktualizujące strukturę bazy danych z kodu (dotnet ef migrations add / database update), oraz CRUD operujący na obiektach zamiast na SQL-u — z automatycznym śledzeniem zmian, które sprawia, że Update to po prostu zmiana właściwości obiektu. To narzędzie o innym kompromisie niż Dapper: mniej kontroli nad dokładnym zapytaniem, w zamian za dużo mniej ręcznie pisanego kodu na co dzień.
🚀 Co dalej?
Zobacz to w praktyce na wideo i pobierz darmową roadmapę, żeby ułożyć naukę w spójną ścieżkę do pierwszej pracy.
- 🗺️ Pobierz darmową roadmapę Junior .NET Developer — 12 kroków od podstaw C# do pierwszej pracy: dev-hobby.pl
- 🎬 Subskrybuj kanał YouTube — nowe filmy co tydzień.
Zamień wiedzę w umiejętności
Pobierz darmową Roadmapę .NET i ułóż takie tematy jak ten w spójną ścieżkę do pierwszej pracy.
Pobieram roadmapę →