C# tutorials > Frameworks and Libraries > Entity Framework Core (EF Core) > Using raw SQL queries and stored procedures
Using raw SQL queries and stored procedures
Entity Framework Core (EF Core) provides an abstraction layer over database interactions, simplifying data access in .NET applications. However, there are situations where bypassing this abstraction and directly executing raw SQL queries or stored procedures becomes necessary or advantageous. This tutorial explores how to execute raw SQL queries and stored procedures using EF Core.
Introduction to Raw SQL Queries
Raw SQL queries allow you to directly execute SQL statements against the database. This is useful for complex queries, performance optimization, or when EF Core's LINQ provider doesn't fully support a specific database feature. EF Core provides methods like FromSqlRaw
and ExecuteSqlRaw
to interact with the database using raw SQL.
Executing a Raw SQL Query with FromSqlRaw
FromSqlRaw
is used to execute a SQL query and map the results to an entity type. In this example, we're retrieving all blogs whose URL contains 'example.com'.
context.Blogs.FromSqlRaw()
to execute the SQL query. The result is then converted to a list of Blog
objects.
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options) : base(options) { }
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
public class Example
{
public static void Run(BloggingContext context)
{
// Execute raw SQL to retrieve blogs
var blogs = context.Blogs
.FromSqlRaw("SELECT * FROM Blogs WHERE Url LIKE '%example.com%'")
.ToList();
foreach (var blog in blogs)
{
Console.WriteLine($"BlogId: {blog.BlogId}, Url: {blog.Url}");
}
}
}
Executing a Raw SQL Query with Parameters
Parameterized queries are crucial for preventing SQL injection vulnerabilities. EF Core allows you to include parameters in your raw SQL queries. Important: Always use parameterized queries to avoid SQL injection attacks.
FromSqlRaw
.
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options) : base(options) { }
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
public class Example
{
public static void Run(BloggingContext context)
{
// Execute raw SQL with parameters to prevent SQL injection
string urlFilter = "%example.com%";
var blogs = context.Blogs
.FromSqlRaw("SELECT * FROM Blogs WHERE Url LIKE {0}", urlFilter)
.ToList();
foreach (var blog in blogs)
{
Console.WriteLine($"BlogId: {blog.BlogId}, Url: {blog.Url}");
}
}
}
Executing a Raw SQL Command with ExecuteSqlRaw
ExecuteSqlRaw
is used to execute SQL commands that don't necessarily return entities, such as UPDATE, INSERT, or DELETE statements. It returns the number of rows affected by the command.
context.Database.ExecuteSqlRaw()
to execute the SQL command.rowsAffected
) to determine the success of the operation.
using Microsoft.EntityFrameworkCore;
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options) : base(options) { }
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
public class Example
{
public static void Run(BloggingContext context)
{
// Execute raw SQL to update a blog's URL
string newUrl = "https://newexample.com";
int blogId = 1; // Assuming BlogId 1 exists
int rowsAffected = context.Database
.ExecuteSqlRaw("UPDATE Blogs SET Url = {0} WHERE BlogId = {1}", newUrl, blogId);
Console.WriteLine($"Rows affected: {rowsAffected}");
}
}
Calling Stored Procedures
Stored procedures are precompiled SQL statements stored in the database. They can encapsulate complex logic and improve performance. EF Core allows you to call stored procedures using Note: You need to create the stored procedure in your database first. For example:FromSqlRaw
or ExecuteSqlRaw
.
CREATE PROCEDURE dbo.GetBlogsByUrlLike
@UrlLike NVARCHAR(200)
AS
BEGIN
SELECT * FROM Blogs WHERE Url LIKE @UrlLike
END
FromSqlRaw
to call the stored procedure. The stored procedure should return a result set that maps to an entity.FromSqlRaw
.
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options) : base(options) { }
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
public class Example
{
public static void Run(BloggingContext context)
{
// Call a stored procedure that returns blogs
var blogs = context.Blogs
.FromSqlRaw("EXECUTE dbo.GetBlogsByUrlLike {0}", "%example.com%")
.ToList();
foreach (var blog in blogs)
{
Console.WriteLine($"BlogId: {blog.BlogId}, Url: {blog.Url}");
}
}
}
Concepts Behind the Snippet
The snippets demonstrate the core principles of using raw SQL and stored procedures with EF Core:
Real-Life Use Case
Imagine you have a complex reporting requirement that is difficult to achieve using EF Core's LINQ provider. You could create a stored procedure that performs the complex calculations and then call that stored procedure from your C# code using Another common use case is bulk data import. Using raw SQL with the FromSqlRaw
, mapping the results to a DTO (Data Transfer Object).SqlBulkCopy
class often provides significantly better performance than inserting records one-by-one through EF Core.
Best Practices
Interview Tip
Be prepared to discuss the trade-offs between using LINQ and raw SQL. Explain when you would choose one over the other, and why. Highlight the importance of security when using raw SQL queries, particularly the use of parameterized queries to prevent SQL injection attacks. Also, be prepared to discuss scenarios where stored procedures provide performance benefits.
When to Use Them
Use raw SQL queries or stored procedures when:
Memory Footprint
The memory footprint of using raw SQL queries and stored procedures depends on the size of the result set. If you're retrieving a large number of rows, consider using techniques like pagination to reduce memory consumption.
Alternatives
Alternatives to raw SQL and stored procedures include:
Pros
Cons
FAQ
-
How do I prevent SQL injection when using raw SQL queries?
Always use parameterized queries. Pass parameters as arguments toFromSqlRaw
orExecuteSqlRaw
. EF Core will handle the proper escaping of the values. -
When should I use raw SQL queries instead of LINQ?
Use raw SQL when you need to optimize performance for specific queries, when you require database-specific features not supported by EF Core's LINQ provider, or when you have existing stored procedures you want to leverage. -
How do I call a stored procedure that returns multiple result sets?
EF Core has limited support for multiple result sets directly throughFromSqlRaw
. You might need to use ADO.NET directly or consider restructuring your stored procedure to return a single result set, or using a separate query for each result set within the stored procedure (if possible). -
Can I use raw SQL for all database operations?
While you technically can, it's generally not recommended. Stick to LINQ for most CRUD operations to benefit from type safety, change tracking, and other features of EF Core. Reserve raw SQL for specific scenarios where LINQ is insufficient or inefficient.