C# tutorials > Language Integrated Query (LINQ) > LINQ to Entities (Entity Framework Core) > Using LINQ with stored procedures

Using LINQ with stored procedures

Using LINQ with Stored Procedures in Entity Framework Core

This tutorial explores how to integrate LINQ (Language Integrated Query) with stored procedures using Entity Framework Core (EF Core). Stored procedures provide a way to encapsulate database logic and improve performance. Combining them with LINQ allows you to leverage the power of LINQ's query syntax and EF Core's object-relational mapping capabilities.

Introduction

Entity Framework Core allows you to execute stored procedures and map the results to entities or simple types. This approach offers flexibility when dealing with complex database operations or when you want to take advantage of pre-optimized stored procedures. We'll cover different ways to call stored procedures using EF Core and LINQ.

Setting up the Database Context

First, define your database context. This context represents a session with the database and allows you to query and save data. Ensure your context includes DbSet properties for the entities you want to interact with. Replace Blog and Post with your actual entity classes.

public class BloggingContext : DbContext
{
    public BloggingContext(DbContextOptions<BloggingContext> options) : base(options) { }

    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>().ToTable("Blogs");
        modelBuilder.Entity<Post>().ToTable("Posts");
    }
}

Defining Entities

Define the entities that represent your database tables. These entities will be used to map the results from the stored procedures. Ensure that the properties in the entities match the columns returned by the stored procedure.

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; }
}

Calling a Stored Procedure with FromSqlRaw

The FromSqlRaw method allows you to execute raw SQL queries, including stored procedures. It returns an IQueryable of the specified entity type. Replace GetBlogsByUrl with the actual name of your stored procedure and {0} with the parameter placeholder. The ToList() method executes the query and returns the results as a list of Blog objects.

using Microsoft.EntityFrameworkCore;

// Example: Getting blogs by URL using a stored procedure
public List<Blog> GetBlogsByUrl(string url)
{
    using (var context = new BloggingContext(options))
    {
        return context.Blogs.FromSqlRaw("EXECUTE GetBlogsByUrl {0}", url).ToList();
    }
}

Calling a Stored Procedure with Parameters

You can pass multiple parameters to the stored procedure using placeholders. Ensure the order of the parameters in the FromSqlRaw method matches the order of the parameters in the stored procedure definition. Replace GetPostsByBlogIdAndTitle with the actual name of your stored procedure. The {0} and {1} are placeholders for blogId and title respectively.

// Example:  Passing multiple parameters
public List<Post> GetPostsByBlogIdAndTitle(int blogId, string title)
{
    using (var context = new BloggingContext(options))
    {
        return context.Posts.FromSqlRaw("EXECUTE GetPostsByBlogIdAndTitle {0}, {1}", blogId, title).ToList();
    }
}

Mapping Results to a Different Entity

If the stored procedure returns a different structure than your existing entities, you can define a new class to map the results. Create a DbSet for the new class using context.Set() and then use FromSqlRaw to execute the stored procedure. This allows you to work with the results in a type-safe manner.

// Suppose the stored procedure returns a different structure
public class BlogSummary
{
    public int BlogId { get; set; }
    public string Url { get; set; }
    public int PostCount { get; set; }
}

//Calling the stored procedure
public List<BlogSummary> GetBlogSummaries()
{
    using (var context = new BloggingContext(options))
    {
        return context.Set<BlogSummary>().FromSqlRaw("EXECUTE GetBlogSummaries").ToList();
    }
}

Executing Stored Procedures for Non-Query Operations

For stored procedures that perform non-query operations, such as inserting, updating, or deleting data, you can use the ExecuteSqlRaw method. This method executes the SQL command and returns the number of rows affected. In this example, `InsertBlog` is a stored procedure that inserts a new blog into the database.

// Example: Inserting a new blog using a stored procedure
public void InsertBlog(string url)
{
    using (var context = new BloggingContext(options))
    {
        context.Database.ExecuteSqlRaw("EXECUTE InsertBlog {0}", url);
    }
}

Concepts Behind the Snippet

The core concept is leveraging the power of stored procedures for specific database operations while integrating them seamlessly within your EF Core application. FromSqlRaw and ExecuteSqlRaw are the key methods for executing stored procedures. Mapping the results to entities allows you to work with the data in a type-safe and object-oriented manner.

Real-Life Use Case

Imagine a scenario where you need to generate complex reports based on aggregated data. Instead of performing complex calculations in your application code, you can create a stored procedure that handles the aggregation logic and returns the results. Your application can then call this stored procedure using EF Core and display the report to the user. Another case would be for importing data from another system, applying data validation and complex business rules using stored procedures to guarantee data consistency and integrity.

Best Practices

  • Use Parameterized Queries: Always use parameterized queries to prevent SQL injection vulnerabilities.
  • Handle Errors: Implement proper error handling to catch exceptions and log errors.
  • Keep Stored Procedures Focused: Design stored procedures to perform specific tasks.
  • Test Thoroughly: Test stored procedures with various inputs to ensure they work correctly.
  • Use Transactions: Use transactions to ensure data consistency, especially for operations that involve multiple tables.
  • Consider Performance: Analyze the execution plan of your stored procedures to identify performance bottlenecks.

Interview Tip

Be prepared to discuss the benefits and drawbacks of using stored procedures with EF Core. Highlight the performance advantages of stored procedures and the importance of using parameterized queries to prevent SQL injection. Also, be ready to explain how to map the results of stored procedures to entities or simple types.

When to Use Them

Use stored procedures when you need to perform complex database operations, improve performance, or encapsulate database logic. They are also useful for enforcing data integrity and security. Consider using them if the logic is better placed in the database tier and accessible by multiple applications, preventing code duplication across different clients.

Memory Footprint

Using stored procedures can potentially reduce the memory footprint on the application server, as the database server handles the complex calculations and data manipulation. The application server only receives the final results, minimizing the amount of data transferred and processed in the application's memory. However, this depends on how the stored procedure and the equivalent LINQ query are written and optimized.

Alternatives

Instead of stored procedures, you could perform all the data manipulation and calculations directly within your C# code using LINQ. You could also use database views to simplify complex queries. Another alternative is to use more advanced features of EF Core, like compiled queries, to optimize LINQ queries.

Pros

  • Performance: Stored procedures can be optimized for performance by the database engine.
  • Security: They can help prevent SQL injection attacks when used with parameterized queries.
  • Encapsulation: They encapsulate database logic, making it easier to maintain and reuse.
  • Data Integrity: Stored procedures can enforce data integrity rules at the database level.

Cons

  • Maintainability: Stored procedures can be harder to maintain than C# code, especially for complex logic.
  • Debugging: Debugging stored procedures can be more challenging than debugging C# code.
  • Vendor Lock-in: Stored procedures are specific to the database vendor.
  • Deployment: Stored procedures need to be deployed and managed separately from the application code.

FAQ

  • How do I pass parameters to a stored procedure using EF Core?

    You can pass parameters to a stored procedure using placeholders in the SQL query and providing the parameter values as arguments to the FromSqlRaw or ExecuteSqlRaw methods.
  • How do I map the results of a stored procedure to an entity?

    You can use the FromSqlRaw method and specify the entity type as the return type. EF Core will automatically map the results to the entity properties.
  • Can I use LINQ to filter the results of a stored procedure?

    Yes, you can use LINQ to filter the results of a stored procedure by chaining LINQ operators after the FromSqlRaw method.