SQL bruto, procedimentos armazenados e interpolação
Execute SQL bruto com segurança usando FromSqlRaw, FromSqlInterpolated e procedimentos armazenados, evitando injeções.
SQL bruto, procedimentos armazenados e interpolação é uma aula grátis de C# Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C# Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C# Academy inclui 4 aulas no total.
Quando usar SQL bruto no EF Core
A maioria das consultas funciona bem com LINQ, mas alguns cenários exigem SQL bruto: análises complexas, funções específicas do fornecedor, procedimentos armazenados ou consultas críticas para o desempenho que o LINQ traduz de forma inadequada.
O EF Core oferece maneiras seguras de usar SQL bruto sem sacrificar a segurança.
FromSqlRaw: consultas parametrizadas seguras
FromSqlRaw executa SQL bruto e mapeia os resultados de volta para as entidades. Sempre use marcadores {0} — nunca concatenação de strings — para evitar injeção de SQL.
// 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: segurança com interpolação
FromSqlInterpolated aceita uma string interpolada de C#. O EF Core converte automaticamente os valores interpolados em parâmetros SQL — uma opção segura e legível.
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 automaticallyCompondo LINQ após FromSql
Você pode encadear operadores LINQ após FromSql. O EF Core envolve o SQL bruto em uma subconsulta e aplica o LINQ sobre ela, o que é útil para adicionar filtragem ou paginação.
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 ...Executando procedimentos armazenados
Chame procedimentos armazenados que retornam linhas de entidades usando FromSqlRaw. Para procedimentos que não retornam linhas (por exemplo, INSERT/UPDATE), use 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 para DML
ExecuteSqlInterpolated executa instruções DML (INSERT, UPDATE, DELETE) com a segurança de strings interpoladas. Ele retorna o número de linhas afetadas.
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");Consultando tipos que não são entidades
Use SqlQuery<T> (.NET 7+) para consultar tipos escalares ou DTO arbitrários que não são entidades do EF Core. Não é necessário usar 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);Tipos de entidade sem chave para exibições
Mapeie uma exibição do banco de dados ou o resultado de uma consulta bruta para um tipo de entidade sem chave usando HasNoKey() e ToView(). Consulte-o como um DbSet, sem precisar de uma chave primária.
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();Evitando armadilhas de injeção de SQL
A regra de ouro: nunca concatene a entrada do usuário em strings SQL. Sempre use consultas parametrizadas por meio dos marcadores de FromSqlRaw, de FromSqlInterpolated ou do LINQ do 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 + "'");Parâmetros de saída com alternativa ADO.NET
O EF Core não oferece suporte nativo a parâmetros de saída de procedimentos armazenados. Nesses casos, recorra ao 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;Na prática: alternativa para pesquisa de texto completo
O LINQ não consegue expressar predicados de pesquisa de texto completo específicos do banco de dados. Use FromSqlInterpolated para aproveitar os recursos nativos de FREETEXT ou tsvector.
string query = "keyboard mechanical";
var results = await _db.Products
.FromSqlInterpolated(
$"SELECT * FROM Products WHERE FREETEXT(Name, {query})")
.AsNoTracking()
.Take(20)
.ToListAsync();Verificação rápida
Por que FromSqlInterpolated é mais seguro do que a concatenação de strings em consultas parametrizadas?
Recapitulação: SQL bruto no EF Core
Principais conclusões:
FromSqlRaw: use marcadores {0}; nunca concatene a entrada do usuárioFromSqlInterpolated: strings interpoladas seguras → parâmetros ADO.NET- Encadeie operadores LINQ após FromSql para adicionar filtragem, ordenação e paginação
ExecuteSqlInterpolatedAsync: execução segura de DMLSqlQuery<T>: consulte DTOs que não são entidades (.NET 7+)- Use ADO.NET diretamente para parâmetros de saída ou procedimentos armazenados complexos
Perguntas Frequentes
A aula “SQL bruto, procedimentos armazenados e interpolação” é grátis?
Sim — o texto completo de “SQL bruto, procedimentos armazenados e interpolação” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C# Academy, atualize para CoddyKit PRO. O curso de C# Academy inclui 4 aulas no total.
O que vou aprender em “SQL bruto, procedimentos armazenados e interpolação”?
Execute SQL bruto com segurança usando FromSqlRaw, FromSqlInterpolated e procedimentos armazenados, evitando injeções. Você pratica C# Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar C# Academy?
Nenhuma experiência prévia é necessária. C# Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “SQL bruto, procedimentos armazenados e interpolação”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de C# Academy?
Sim. Cada aula de C# Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Carregamento imediato, tardio e explícito
- SQL bruto, procedimentos armazenados e interpolação
- Consultas compiladas e desempenho
- Filtros globais de consulta e entidades próprias