Introduction

Entity Framework Core (EF Core) is a powerful ORM in .NET that helps developers work with databases using C# instead of writing raw SQL queries. However, there are real-world scenarios where using raw SQL becomes necessary—for performance optimization, complex queries, or working with stored procedures.

But here is the challenge: if raw SQL is not handled properly, it can lead to SQL Injection attacks, which are one of the most common and dangerous security risks in web applications.

What is SQL Injection?

SQL Injection is a security vulnerability where an attacker can manipulate your SQL query by injecting malicious input.

Example of unsafe code:

var user = context.Users
    .FromSqlRaw($"SELECT * FROM Users WHERE Name = '{userInput}'")
    .FirstOrDefault();

If userInput is:

' OR 1=1 --

Then your query becomes:

SELECT * FROM Users WHERE Name = '' OR 1=1 --

This can expose all data in your database.

Why Use Raw SQL in EF Core?

Even though EF Core supports LINQ, raw SQL is useful for:

But it must be used carefully.

Safe Ways to Use Raw SQL in EF Core

Use Parameterized Queries (Most Important)

The safest way to prevent SQL injection is to use parameterized queries.

Example:

var user = context.Users
    .FromSqlRaw("SELECT * FROM Users WHERE Name = @name",
        new SqlParameter("@name", userInput))
    .FirstOrDefault();

Why it is safe:

Use FromSqlInterpolated (Safer Alternative)

EF Core provides a safer method:

var user = context.Users
    .FromSqlInterpolated($"SELECT * FROM Users WHERE Name = {userInput}")
    .FirstOrDefault();

Why it is safe:

This is recommended over string concatenation.

Avoid String Concatenation (Dangerous)

Never do this:

var query = "SELECT * FROM Users WHERE Name = '" + userInput + "'";

This directly exposes your application to SQL injection.

Use Stored Procedures Safely

Stored procedures can also be safe if used correctly.

Example:

var users = context.Users
    .FromSqlRaw("EXEC GetUserByName @name",
        new SqlParameter("@name", userInput))
    .ToList();

Always pass parameters instead of concatenating strings.

Validate User Input

Even with parameterized queries, input validation is important.

Best practices:

Example:

if (string.IsNullOrWhiteSpace(userInput))
{
    throw new ArgumentException("Invalid input");
}

Use Least Privilege Database Access

Your database connection should have limited permissions.

Example:

This reduces damage even if an attack occurs.

Use Logging and Monitoring

Track database queries and unusual behavior.

Benefits:

Tools:

Prefer LINQ When Possible

EF Core LINQ queries are automatically safe from SQL injection.

Example:

var user = context.Users
    .FirstOrDefault(u => u.Name == userInput);

LINQ translates into parameterized SQL internally.

Use raw SQL only when necessary.

Common Mistakes Developers Make

Using FromSqlRaw with String Interpolation

FromSqlRaw($"SELECT * FROM Users WHERE Name = '{userInput}'")

❌ Unsafe

Trusting User Input Blindly

Never assume input is safe.

Overusing Raw SQL

Use raw SQL only when needed.

Ignoring Security Testing

Always test your application for vulnerabilities.

Real-World Example

Let’s build a safe search API:

app.MapGet("/users/{name}", (string name, AppDbContext context) =>
{
    var users = context.Users
        .FromSqlInterpolated($"SELECT * FROM Users WHERE Name = {name}")
        .ToList();

    return users;
});

This ensures:

Best Practices Summary

Summary

Using raw SQL in Entity Framework Core is sometimes necessary, but it must be done carefully to avoid SQL injection risks. By using parameterized queries, FromSqlInterpolated, input validation, and proper security practices, developers can safely execute raw SQL queries. Following these best practices ensures secure, scalable, and production-ready .NET applications.