Entity Framework Core Queries

This document covers how to retrieve data from your database using Entity Framework Core (EF Core) queries. EF Core offers powerful and flexible ways to query your data, from simple lookups to complex projections and filtering.

Introduction to Querying

EF Core uses LINQ (Language Integrated Query) to allow you to write queries in C# or VB.NET that are strongly typed and compiled. This provides a more productive and less error-prone querying experience compared to raw SQL.

LINQ to Entities

EF Core translates your LINQ queries into SQL statements that are executed against the database. The primary way to initiate a query is by accessing the DbSet<TEntity> property on your DbContext instance.

Basic Query Example

Let's assume you have a DbContext named MyDbContext with a DbSet<Product> property:

var context = new MyDbContext();
var products = await context.Products.ToListAsync();

Filtering Data

You can use LINQ's Where operator to filter your results based on specific criteria.

Filtering by Price

var expensiveProducts = await context.Products
    .Where(p => p.Price > 100)
    .ToListAsync();

Sorting Data

Use OrderBy and OrderByDescending to sort your results.

Sorting by Name (Ascending)

var sortedProducts = await context.Products
    .OrderBy(p => p.Name)
    .ToListAsync();

Projection

Projection allows you to select specific properties from your entities, creating new anonymous types or predefined DTOs (Data Transfer Objects).

Projecting Product Names and Prices

var productNamesAndPrices = await context.Products
    .Select(p => new { p.Name, p.Price })
    .ToListAsync();

// Iterate through the results
foreach (var item in productNamesAndPrices)
{
    Console.WriteLine($"{item.Name}: {item.Price:C}");
}

Including Related Data (Navigation Properties)

EF Core supports eager loading related entities using the Include and ThenInclude methods.

Including Orders for a Customer

var customerWithOrders = await context.Customers
    .Include(c => c.Orders)
    .FirstOrDefaultAsync(c => c.Id == 1);

if (customerWithOrders != null)
{
    Console.WriteLine($"Customer: {customerWithOrders.Name}");
    foreach (var order in customerWithOrders.Orders)
    {
        Console.WriteLine($"- Order ID: {order.Id}, Date: {order.OrderDate}");
    }
}
Tip: Use ThenInclude to chain multiple levels of eager loading for complex relationships.

Executing Raw SQL Queries

In some scenarios, you might need to execute raw SQL queries. EF Core provides methods for this as well.

Executing a Raw SQL Query

var productsFromSql = await context.Products
    .FromSqlRaw("SELECT * FROM Products WHERE Price > {0}", 50)
    .ToListAsync();
Note: When using FromSqlRaw or FromSqlInterpolated, EF Core doesn't track changes to the entities returned by the query by default.

Querying with Parameters

It's crucial to use parameterized queries to prevent SQL injection vulnerabilities.

Parameterized Query Example

var productName = "Laptop";
var product = await context.Products
    .FirstOrDefaultAsync(p => p.Name == productName);

Paging Data

Implement paging using Skip and Take operators.

Get the Second Page of Products (10 items per page)

int pageNumber = 2;
int pageSize = 10;

var productsPage = await context.Products
    .OrderBy(p => p.Name)
    .Skip((pageNumber - 1) * pageSize)
    .Take(pageSize)
    .ToListAsync();

Conclusion

Mastering EF Core queries is essential for efficiently retrieving and manipulating data in your applications. Explore the various LINQ operators and EF Core specific methods to build robust and performant data access logic.