0Pricing
C# Academy · Aula

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 automatically

Compondo 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ário
  • FromSqlInterpolated: 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 DML
  • SqlQuery<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

  1. Carregamento imediato, tardio e explícito
  2. SQL bruto, procedimentos armazenados e interpolação
  3. Consultas compiladas e desempenho
  4. Filtros globais de consulta e entidades próprias
← Voltar para C# Academy