Ce face EF Core: interogări (Where, Include, AsNoTracking)
Pe un DbSet<T> scrii LINQ obișnuit, iar EF Core îl traduce în SQL abia când rezultatul e cerut: la ToList/ToListAsync, First, Count, Any sau la parcurgere. Select cu un tip anonim sau un DTO aduce din baza de date doar coloanele de care ai nevoie.
Relațiile nu se încarcă automat: Include(c => c.Elevi) aduce și elevii fiecărei clase, în aceeași interogare. AsNoTracking() spune contextului să nu urmărească obiectele, ceea ce e mai rapid pentru date doar de afișat.
ExecuteUpdateAsync și ExecuteDeleteAsync (EF Core 7) trimit direct un UPDATE/DELETE fără să încarce rândurile în memorie. Variantele Async ale metodelor sunt recomandate în aplicațiile web.
Exemple
Exemplul 1: Filtrare, proiecție și Include
using Microsoft.EntityFrameworkCore;
using var db = new ScoalaContext();
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
var c9a = new Clasa { Nume = "9A" };
var c9b = new Clasa { Nume = "9B" };
db.Elevi.AddRange(
new Elev { Nume = "Ana", Media = 9, Clasa = c9a },
new Elev { Nume = "Mihai", Media = 7, Clasa = c9a },
new Elev { Nume = "Ioana", Media = 10, Clasa = c9b });
db.SaveChanges();
var buni = db.Elevi.AsNoTracking()
.Where(e => e.Media >= 8)
.OrderByDescending(e => e.Media)
.Select(e => new { e.Nume, Clasa = e.Clasa.Nume })
.ToList();
foreach (var e in buni)
Console.WriteLine($"{e.Nume} ({e.Clasa})");
foreach (var c in db.Clase.Include(k => k.Elevi).OrderBy(k => k.Nume))
Console.WriteLine($"{c.Nume}: elevi {c.Elevi.Count}");
public class Clasa
{
public int Id { get; set; }
public string Nume { get; set; } = "";
public List<Elev> Elevi { get; set; } = [];
}
public class Elev
{
public int Id { get; set; }
public string Nume { get; set; } = "";
public int Media { get; set; }
public int ClasaId { get; set; }
public Clasa Clasa { get; set; } = null!;
}
public class ScoalaContext : DbContext
{
public DbSet<Elev> Elevi => Set<Elev>();
public DbSet<Clasa> Clase => Set<Clasa>();
protected override void OnConfiguring(DbContextOptionsBuilder options) =>
options.UseSqlite("Data Source=scoala.db");
}
Rezultat
Ioana (9B)
Ana (9A)
9A: elevi 2
9B: elevi 1
Exemplul 2: Metode async și actualizare în masă
Continuă exemplul 1, cu aceleași date. ExecuteUpdateAsync mărește media lui Mihai direct în baza de date.
int actualizati = await db.Elevi
.Where(e => e.Media < 8)
.ExecuteUpdateAsync(s => s.SetProperty(e => e.Media, e => e.Media + 1));
Console.WriteLine($"Actualizați: {actualizati}");
Console.WriteLine(await db.Elevi.CountAsync(e => e.Clasa.Nume == "9A"));
Console.WriteLine(await db.Elevi.AnyAsync(e => e.Nume == "Radu"));
Console.WriteLine(await db.Elevi.MinAsync(e => e.Media));
var primul = await db.Elevi.OrderByDescending(e => e.Media).FirstAsync();
Console.WriteLine(primul.Nume);
Rezultat
Actualizați: 1
2
False
8
Ioana
Greșeli frecvente
- Accesarea
c.ElevifărăInclude: colecția e goală (sau, cu lazy loading activat, fiecare acces face o interogare separată, problema N+1). ToList()pus prea devreme (db.Elevi.ToList().Where(...)): toată tabela este adusă în memorie și filtrată acolo.- Apeluri de metode C# proprii în
Wherenu se pot traduce în SQL și aruncăInvalidOperationExceptionla rulare.
Comenzi înrudite
Entity Framework Core: DbContext și DbSet: DbContext este legătura cu baza de date în EF Core: DbSet<T> reprezintă un tabel, iar SaveChanges salvează adăugările, modificările și ștergerile.EF Core: migrări (dotnet ef migrations): Migrările țin schema bazei de date în pas cu modelul C#: migrations add generează codul schimbării, database update o aplică.Skip / Take (paginare): Take ia primele n elemente, Skip le sare; împreună fac paginare. TakeWhile/SkipWhile se opresc la prima condiție falsă.