SQL nativo, stored procedure e interpolazione
Esegua SQL nativo in modo sicuro con FromSqlRaw, FromSqlInterpolated e stored procedure, evitando le injection.
SQL nativo, stored procedure e interpolazione è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 4 lezioni in totale.
Quando usare SQL raw in EF Core
La maggior parte delle query funziona bene con LINQ, ma alcuni scenari richiedono SQL raw: analisi complesse, funzioni specifiche del fornitore, stored procedure o query critiche per le prestazioni che LINQ traduce in modo inefficiente.
EF Core offre modalità sicure per utilizzare SQL raw senza compromettere la sicurezza.
FromSqlRaw: query parametrizzate sicure
FromSqlRaw esegue SQL raw e riconverte i risultati in entità. Utilizzi sempre segnaposto {0} — mai la concatenazione di stringhe — per prevenire l'SQL injection.
// SAFE: parameterized
var products = await _db.Products
.FromSqlRaw("SELECT * FROM Products WHERE Price > {0}", 100m)
.ToListAsync();
// DANGEROUS: never do this
// FromSqlRaw("SELECT * FROM Products WHERE Price > " + price)FromSqlInterpolated: sicurezza delle stringhe interpolate
FromSqlInterpolated accetta una stringa interpolata C#. EF Core converte automaticamente i valori interpolati in parametri SQL: una soluzione sicura e leggibile.
decimal minPrice = 100m;
string category = "Electronics";
var products = await _db.Products
.FromSqlInterpolated(
$"SELECT * FROM Products WHERE Price > {minPrice} AND Category = {category}")
.OrderBy(p => p.Name)
.ToListAsync();
// Values become @p0, @p1 parameters automaticallyComporre query LINQ dopo FromSql
È possibile concatenare operatori LINQ dopo FromSql. EF Core racchiude il vostro SQL raw in una sottoquery e applica LINQ al di sopra, una soluzione utile per aggiungere filtri o la paginazione.
decimal min = 50m;
var page = await _db.Products
.FromSqlInterpolated($"SELECT * FROM Products WHERE Price > {min}")
.Where(p => p.IsActive) // additional LINQ filter
.OrderBy(p => p.Price)
.Skip(0).Take(20) // pagination
.ToListAsync();
// Generates: SELECT ... FROM (raw SQL) AS p WHERE ...Eseguire stored procedure
Richiami le stored procedure che restituiscono righe di entità tramite FromSqlRaw. Per le procedure che non restituiscono righe (ad esempio INSERT/UPDATE), utilizzi ExecuteSqlRawAsync.
// Stored proc returning Products
var products = await _db.Products
.FromSqlRaw("EXEC GetProductsByCategory {0}", "Books")
.ToListAsync();
// Stored proc with no return rows
await _db.Database.ExecuteSqlRawAsync(
"EXEC ArchiveOldOrders {0}",
DateTime.UtcNow.AddYears(-1));ExecuteSqlInterpolated per il DML
ExecuteSqlInterpolated esegue istruzioni DML (INSERT, UPDATE, DELETE) con la sicurezza delle stringhe interpolate. Restituisce il numero di righe interessate.
int days = 30;
int affected = await _db.Database.ExecuteSqlInterpolatedAsync(
$"UPDATE Orders SET Status = 'Expired' WHERE PlacedAt < {DateTime.UtcNow.AddDays(-days)}");
Console.WriteLine($"{affected} orders expired");Eseguire query su tipi non appartenenti a entità
Utilizzi SqlQuery<T> (.NET 7+) per eseguire query su tipi scalari o DTO arbitrari che non sono entità EF Core. Non è necessario alcun DbSet.
// Query a DTO directly — no entity needed
var stats = await _db.Database
.SqlQuery<ProductStats>(
$"SELECT Category, COUNT(*) AS Count, AVG(Price) AS AvgPrice FROM Products GROUP BY Category")
.ToListAsync();
public record ProductStats(string Category, int Count, decimal AvgPrice);Tipi di entità senza chiave per le viste
Esegua il mapping di una vista del database o del risultato di una query raw a un tipo di entità senza chiave usando HasNoKey() e ToView(). Potrà eseguire query come su un DbSet senza aver bisogno di una chiave primaria.
public class ProductSalesSummary
{
public string Category { get; set; } = "";
public int TotalSold { get; set; }
public decimal Revenue { get; set; }
}
// In OnModelCreating:
modelBuilder.Entity<ProductSalesSummary>()
.HasNoKey()
.ToView("vw_ProductSalesSummary");
// Query:
var summary = await _db.Set<ProductSalesSummary>().ToListAsync();Evitare le insidie dell'SQL injection
La regola d'oro: non concatenare mai l'input dell'utente nelle stringhe SQL. Utilizzi sempre query parametrizzate tramite i segnaposto di FromSqlRaw, FromSqlInterpolated o LINQ di EF Core.
// SAFE
var name = userInput;
var result = await _db.Products
.FromSqlInterpolated($"SELECT * FROM Products WHERE Name = {name}")
.ToListAsync();
// INJECTION RISK (never do this)
// FromSqlRaw("SELECT * FROM Products WHERE Name = '" + name + "'");Parametri di output con fallback ad ADO.NET
EF Core non supporta nativamente i parametri di output delle stored procedure. In questi casi, ricorra ad ADO.NET usando _db.Database.GetDbConnection().
await _db.Database.OpenConnectionAsync();
var conn = _db.Database.GetDbConnection();
using var cmd = conn.CreateCommand();
cmd.CommandText = "EXEC GetOrderCount @CustomerId, @Count OUTPUT";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@CustomerId", 5));
var outParam = new SqlParameter("@Count", SqlDbType.Int) { Direction = ParameterDirection.Output };
cmd.Parameters.Add(outParam);
await cmd.ExecuteNonQueryAsync();
int count = (int)outParam.Value;Nella pratica: fallback per la ricerca full-text
LINQ non consente di esprimere i predicati di ricerca full-text specifici del database. Utilizzi FromSqlInterpolated per sfruttare le funzionalità native FREETEXT o tsvector.
string query = "keyboard mechanical";
var results = await _db.Products
.FromSqlInterpolated(
$"SELECT * FROM Products WHERE FREETEXT(Name, {query})")
.AsNoTracking()
.Take(20)
.ToListAsync();Verifica rapida
Perché FromSqlInterpolated è più sicuro della concatenazione di stringhe per le query parametrizzate?
Riepilogo: SQL raw in EF Core
Punti chiave:
FromSqlRaw: utilizzi segnaposto {0}; non concateni mai l'input dell'utenteFromSqlInterpolated: stringhe interpolate sicure → parametri ADO.NET- Concateni operatori LINQ dopo FromSql per aggiungere filtri, ordinamento e paginazione
ExecuteSqlInterpolatedAsync: esecuzione sicura del DMLSqlQuery<T>: esecuzione di query su DTO non appartenenti a entità (.NET 7+)- Utilizzi direttamente ADO.NET per i parametri di output o le stored procedure complesse
Domande Frequenti
La lezione «SQL nativo, stored procedure e interpolazione» è gratuita?
Sì — il testo completo di «SQL nativo, stored procedure e interpolazione» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 4 lezioni in totale.
Cosa imparerò in «SQL nativo, stored procedure e interpolazione»?
Esegua SQL nativo in modo sicuro con FromSqlRaw, FromSqlInterpolated e stored procedure, evitando le injection. Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare C# Academy?
Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «SQL nativo, stored procedure e interpolazione»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione C# Academy?
Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Caricamento eager, lazy ed esplicito
- SQL nativo, stored procedure e interpolazione
- Query compilate e prestazioni
- Filtri globali per le query ed entità possedute