0Pricing
C# Academy · Lección

SQL sin formato, procedimientos almacenados e interpolación

Ejecute SQL sin formato de forma segura con FromSqlRaw, FromSqlInterpolated y procedimientos almacenados, evitando la inyección.

SQL sin formato, procedimientos almacenados e interpolación es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 4 lecciones en total.

Cuándo utilizar SQL sin formato en EF Core

La mayoría de las consultas funcionan correctamente con LINQ, pero algunos escenarios requieren SQL sin formato: análisis complejos, funciones específicas del proveedor, procedimientos almacenados o consultas críticas para el rendimiento que LINQ traduce de forma deficiente.

EF Core ofrece formas seguras de utilizar SQL sin formato sin sacrificar la seguridad.

FromSqlRaw: consultas parametrizadas seguras

FromSqlRaw ejecuta SQL sin formato y vuelve a asignar los resultados a entidades. Utilice siempre marcadores de posición {0} — nunca concatenación de cadenas — para evitar la inyección 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: seguridad con interpolación

FromSqlInterpolated acepta una cadena interpolada de C#. EF Core convierte automáticamente los valores interpolados en parámetros SQL, de forma segura y legible.

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

Composición de LINQ después de FromSql

Puede encadenar operadores de LINQ después de FromSql. EF Core envuelve el SQL sin formato como una subconsulta y aplica LINQ sobre ella, lo que resulta útil para añadir filtros o paginación.

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 ...

Ejecución de procedimientos almacenados

Llame a procedimientos almacenados que devuelvan filas de entidades mediante FromSqlRaw. Para los procedimientos que no devuelven filas (por ejemplo, INSERT/UPDATE), utilice 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 ejecuta instrucciones DML (INSERT, UPDATE, DELETE) con la seguridad de las cadenas interpoladas. Devuelve el número de filas afectadas.

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");

Consulta de tipos que no son entidades

Utilice SqlQuery<T> (.NET 7+) para consultar tipos escalares o DTO arbitrarios que no sean entidades de EF Core. No se requiere ningún 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 entidad sin clave para vistas

Asigne una vista de base de datos o el resultado de una consulta sin formato a un tipo de entidad sin clave mediante HasNoKey() y ToView(). Consúltelo como un DbSet sin necesidad de una clave principal.

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();

Cómo evitar errores de inyección SQL

La regla de oro: nunca concatene la entrada del usuario en cadenas SQL. Utilice siempre consultas parametrizadas mediante los marcadores de posición de FromSqlRaw, FromSqlInterpolated o LINQ de 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 salida con la alternativa de ADO.NET

EF Core no admite de forma nativa los parámetros de salida de los procedimientos almacenados. En esos casos, recurra a ADO.NET mediante _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;

En la práctica: alternativa para la búsqueda de texto completo

LINQ no puede expresar predicados de búsqueda de texto completo específicos de cada base de datos. Utilice FromSqlInterpolated para aprovechar las capacidades nativas de FREETEXT o tsvector.

string query = "keyboard mechanical";
var results = await _db.Products
    .FromSqlInterpolated(
        $"SELECT * FROM Products WHERE FREETEXT(Name, {query})")
    .AsNoTracking()
    .Take(20)
    .ToListAsync();

Comprobación rápida

¿Por qué FromSqlInterpolated es más seguro que la concatenación de cadenas para las consultas parametrizadas?

Resumen: SQL sin formato en EF Core

Conclusiones clave:

  • FromSqlRaw: utilice marcadores de posición {0}; nunca concatene la entrada del usuario
  • FromSqlInterpolated: cadenas interpoladas seguras → parámetros de ADO.NET
  • Encadene operadores de LINQ después de FromSql para añadir filtros, ordenación y paginación
  • ExecuteSqlInterpolatedAsync: ejecución segura de DML
  • SqlQuery<T>: consulta de DTO que no son entidades (.NET 7+)
  • Utilice ADO.NET directamente para parámetros de salida o procedimientos almacenados complejos

Preguntas frecuentes

¿La lección «SQL sin formato, procedimientos almacenados e interpolación» es gratis?

Sí — el texto completo de «SQL sin formato, procedimientos almacenados e interpolación» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 4 lecciones en total.

¿Qué aprenderé en «SQL sin formato, procedimientos almacenados e interpolación»?

Ejecute SQL sin formato de forma segura con FromSqlRaw, FromSqlInterpolated y procedimientos almacenados, evitando la inyección. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C# Academy?

No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.

¿Cuánto tiempo toma la lección «SQL sin formato, procedimientos almacenados e interpolación»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C# Academy?

Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Carga eager, lazy y explícita
  2. SQL sin formato, procedimientos almacenados e interpolación
  3. Consultas compiladas y rendimiento
  4. Filtros de consulta globales y entidades propias
← Volver a C# Academy