Andiamo dritti al punto: cos'è davvero questo framework core?

Se sei arrivato fin qui, probabilmente stai scrivendo codice C# o stai cercando di capire come far parlare la tua applicazione con un database senza dover scrivere migliaia di righe di SQL a mano. Entity Framework Core (che per brevità chiameremo spesso framework core) non è solo un "connettore". È un ORM, un Object-Relational Mapper.

In parole povere? Traduce i tuoi oggetti C# in tabelle del database e viceversa. Sembra magia, ma dietro c'è una logica precisa che, se ignorata, può trasformare la tua app in un mostro lentissimo.

Il problema è che molti sviluppatori lo usano come una scatola nera. Buttano dentro i dati, premono invio e sperano che funzioni. Errore fatale.

Per dominare il framework core devi capire come ragiona. Non puoi limitarti a conoscere la sintassi; devi capire cosa succede "sotto il cofano" quando scrivi una query LINQ.

Code First o Database First? La guerra infinita

Questa è la prima scelta che ti trovi davanti. Molti si bloccano qui per giorni.

L'approccio Code First è quello più amato oggi. Scrivi le tue classi, definisci le relazioni e lasci che EF Core generi il database tramite le migrazioni. È pulito. È veloce. Ti permette di tenere tutto sotto controllo nel codice sorgente.

Poi c'è il Database First. Utile se hai un database legacy, creato anni fa da un DBA che non ha mai visto un computer moderno o se il DB è condiviso tra più applicazioni diverse. In questo caso, il framework core legge lo schema esistente e genera le classi per te.

Quale scegliere? Dipende dal progetto. Ma se parti da zero, vai di Code First. Senza dubbi.

Il pericolo nascosto: il problema delle N+1 query

Qui è dove la maggior parte dei progetti inizia a rallentare vistosamente. Immagina di avere una lista di ordini e di voler stampare il nome del cliente per ogni ordine.

Se scrivi un ciclo che per ogni ordine interroga il database per trovare il cliente, hai appena creato un disastro. Hai fatto 1 query per gli ordini e N query (una per ogni riga) per i clienti. Risultato? Il server database esplode mentre l'utente aspetta che la pagina carichi.

La soluzione si chiama Eager Loading. Usando il metodo .Include(), dici al framework core di recuperare tutto in un'unica soluzione, con una JOIN SQL efficiente.

Un dettaglio non da poco: non abusarne. Se includi ogni singola tabella correlata a ogni query, caricherai megabyte di dati inutili nella RAM del server. L'equilibrio è tutto.

Configurare il modello senza sporcare le classi

Molti principianti usano i Data Annotations. Mettono attributi come [Required] o [StringLength(100)] direttamente sopra le proprietà della classe.

Funziona, certo. Ma rende le tue classi di business dipendenti dal framework. È brutto da vedere e poco flessibile.

La via professionale è la Fluent API. All'interno del metodo OnModelCreating, puoi definire ogni singolo dettaglio della tua tabella: chiavi primarie, indici, vincoli di unicità e relazioni complesse.

Così le tue classi rimangono "pure", semplici contenitori di dati (POCO), mentre tutta la logica di persistenza sta in un unico posto centralizzato. Molto più ordinato.

Performance: quando LINQ non basta più

LINQ è fantastico. Rende il codice leggibile e tipizzato. Però, a volte, il traduttore che trasforma C# in SQL fa scelte discutibili.

Cosa fare quando una query è troppo lenta? Hai tre strade:

  • AsNoTracking(): Se devi solo leggere dati per visualizzarli (senza modificarli), usa questo metodo. Dice al framework core di non monitorare i cambiamenti agli oggetti, risparmiando una quantità enorme di memoria e CPU.
  • Proiezioni: Non fare Select *. Usa un oggetto anonimo o un DTO per prendere solo le tre colonne che ti servono davvero. Meno dati viaggiano sul cavo, più l'app è veloce.
  • SQL Raw: Se la query è un incubo di join e aggregazioni, scrivi SQL puro. Non averne paura. EF Core permette di eseguire comandi raw senza problemi. A volte, un bravo sviluppatore sa quando smettere di usare l'astrazione.

Proprio così. L'astrazione è un aiuto, non una prigione.

Gestire le migrazioni senza traumi

Le migrazioni sono il cuore del versionamento del database. Permettono a tutto il team di avere lo stesso schema senza scambiarsi file .sql via email.

Il trucco per non sbagliare è essere metodici. Ogni modifica al modello deve generare una migrazione con un nome chiaro: AddUserPhoneNumber è meglio di Migration123.

Attenzione però ai cambiamenti distruttivi. Rinominare una colonna in EF Core spesso comporta la cancellazione della vecchia e la creazione di una nuova. Se hai dati reali, perdi tutto. In questi casi, devi intervenire manualmente nel file della migrazione per scrivere un comando sp_rename (se sei su SQL Server).

È un passaggio delicato. Ma è l'unico modo per non perdere i dati dei clienti in produzione.

L'importanza del DbContext

Il DbContext è il cervello dell'operazione. È lui che gestisce la connessione, il tracciamento degli oggetti e le transazioni.

Un errore comune è istanziarlo manualmente con new MyDbContext() in ogni metodo. Sbagliatissimo. Il contesto deve essere iniettato tramite Dependency Injection con un ciclo di vita Scoped. Questo garantisce che ci sia un unico contesto per ogni richiesta HTTP, evitando conflitti di threading e perdite di memoria.

Se stai lavorando su app multi-threaded o background services, avrai bisogno di un IDbContextFactory. Altrimenti, ti scontrerai con l'errore più odiato di sempre: "A second operation was started on this context before a previous operation completed".

Un incubo che si evita con la giusta architettura.

Considerazioni finali per un codice pulito

Usare il framework core non significa delegare tutto alla macchina. Significa usare uno strumento potente per accelerare lo sviluppo, mantenendo però il controllo totale su ciò che accade nel database.

Il segreto? Monitora le query. Usa i log di EF Core in console durante lo sviluppo per vedere esattamente quale SQL viene generato. Se vedi una query che sembra scritta da un bambino di cinque anni, è il momento di rifare il LINQ o passare a SQL raw.

Semplice. Efficace.