C# Academy · Lekcja

Surowy SQL, procedury składowane i interpolacja

Bezpiecznie wykonuj surowy SQL za pomocą FromSqlRaw, FromSqlInterpolated i procedur składowanych, unikając SQL injection.

Lekcja 2 z 413 kroki

Surowy SQL, procedury składowane i interpolacja to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.

Kiedy używać surowego SQL w EF Core

Większość zapytań działa poprawnie z LINQ, ale niektóre scenariusze wymagają surowego SQL: złożonej analityki, funkcji specyficznych dla dostawcy, procedur składowanych lub zapytań o krytycznym znaczeniu dla wydajności, które LINQ tłumaczy nieoptymalnie.

EF Core udostępnia bezpieczne sposoby używania surowego SQL bez rezygnowania z bezpieczeństwa.

FromSqlRaw: bezpieczne zapytania z parametrami

FromSqlRaw wykonuje surowy SQL i mapuje wyniki z powrotem na encje. Należy zawsze używać symboli zastępczych {0} — nigdy konkatenacji ciągów — aby zapobiec 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: bezpieczeństwo interpolacji

FromSqlInterpolated przyjmuje interpolowany ciąg C#. EF Core automatycznie konwertuje interpolowane wartości na parametry SQL, zapewniając bezpieczeństwo i czytelność.

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

Łączenie operatorów LINQ po FromSql

Po FromSql można łączyć operatory LINQ. EF Core opakowuje surowy SQL jako podzapytanie i nakłada na nie operatory LINQ, co jest przydatne przy dodawaniu filtrowania lub stronicowania.

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

Wykonywanie procedur składowanych

Procedury składowane zwracające wiersze encji należy wywoływać za pomocą FromSqlRaw. W przypadku procedur, które nie zwracają wierszy, na przykład INSERT/UPDATE, należy użyć 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 dla instrukcji DML

ExecuteSqlInterpolated wykonuje instrukcje DML (INSERT, UPDATE, DELETE), zapewniając bezpieczeństwo interpolowanych ciągów. Zwraca liczbę zmodyfikowanych wierszy.

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

Odpytywanie typów niebędących encjami

Należy użyć SqlQuery<T> (.NET 7+), aby odpytywać dowolne typy skalarne lub typy DTO, które nie są encjami EF Core. Nie jest wymagany obiekt 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);

Typy encji bez klucza dla widoków

Widok bazy danych lub wynik surowego zapytania można zmapować na typ encji bez klucza za pomocą HasNoKey() i ToView(). Można odpytywać go tak jak obiekt DbSet, bez konieczności definiowania klucza głównego.

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

Unikanie pułapek SQL injection

Najważniejsza zasada: nigdy nie należy łączyć danych wejściowych użytkownika z ciągami SQL. Zawsze należy używać zapytań parametryzowanych za pomocą symboli zastępczych FromSqlRaw, FromSqlInterpolated lub LINQ w 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 + "'");

Parametry wyjściowe z użyciem ADO.NET

EF Core nie obsługuje natywnie parametrów wyjściowych procedur składowanych. W takich przypadkach należy użyć ADO.NET za pośrednictwem _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;

Praktyka: rozwiązanie awaryjne dla wyszukiwania pełnotekstowego

LINQ nie pozwala wyrażać predykatów wyszukiwania pełnotekstowego specyficznych dla bazy danych. Należy użyć FromSqlInterpolated, aby skorzystać z natywnych możliwości FREETEXT lub tsvector.

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

Szybkie sprawdzenie

Dlaczego FromSqlInterpolated jest bezpieczniejsze niż konkatenacja ciągów w przypadku zapytań parametryzowanych?

Podsumowanie: surowy SQL w EF Core

Najważniejsze informacje:

  • FromSqlRaw: należy używać symboli zastępczych {0}; nigdy nie należy łączyć danych wejściowych użytkownika z ciągami
  • FromSqlInterpolated: bezpieczne interpolowane ciągi → parametry ADO.NET
  • Po FromSql można łączyć operatory LINQ, aby dodawać filtrowanie, sortowanie i stronicowanie
  • ExecuteSqlInterpolatedAsync: bezpieczne wykonywanie instrukcji DML
  • SqlQuery<T>: odpytywanie obiektów DTO niebędących encjami (.NET 7+)
  • ADO.NET należy stosować bezpośrednio w przypadku parametrów wyjściowych lub złożonych procedur składowanych
Bezpłatny start

Ucz się C# dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
93
Lekcje
346

Często zadawane pytania

Czy lekcja „Surowy SQL, procedury składowane i interpolacja” jest bezpłatna?

Tak — pełny tekst „Surowy SQL, procedury składowane i interpolacja” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Surowy SQL, procedury składowane i interpolacja”?

Bezpiecznie wykonuj surowy SQL za pomocą FromSqlRaw, FromSqlInterpolated i procedur składowanych, unikając SQL injection. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Surowy SQL, procedury składowane i interpolacja”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Ładowanie eager, lazy i explicit
  2. Surowy SQL, procedury składowane i interpolacja
  3. Zapytania kompilowane i wydajność
  4. Globalne filtry zapytań i encje owned
← Powrót do C# Academy