In Entity Framework, projections allow us to transform the data we obtain from a query.
For example, we can select only the properties or fields that interest us, when working with complex entities that contain many properties, but we only need a subset of them.
To do this, Entity Framework uses the LINQ method Select
, which is responsible for performing these projections, allowing us to define what data we want to retrieve and how we want to structure it.
Projections not only allow us to select only the data we need but can also significantly improve performance.
They actually modify the generated SQL query. By reducing the amount of data transferred from the database, we minimize execution time and memory consumption.
Basic usage of Select
The Select
clause is used to project the results of a query into a new form. Let’s look at a basic example:
var names = context.Users
.Select(u => u.Name)
.ToList();
In this example,
- We select only the
Name
property of theUser
entity. - The result is a list of strings (
List<string>
) that contains the names of all users.
Projection of multiple properties
If we need to select more than one property, we can do so using an anonymous type:
var users = context.Users
.Select(u => new
{
u.Name,
u.Email
})
.ToList();
Here,
- We are creating an anonymous type that contains the
Name
andEmail
properties of each user. - The result is a list of anonymous objects, each with these two properties.
Anonymous types are a feature of C# that allows us to create objects without the need to define an explicit class. They are especially useful in LINQ queries, where we often need temporary data structures.
Advanced projections
Projections with relationships between entities
When working with related entities, projections allow us to include data from related entities in our results. For example:
var orders = context.Orders
.Select(o => new
{
o.Id,
o.Date,
CustomerName = o.Customer.Name,
Total = o.Details.Sum(d => d.Quantity * d.Price)
})
.ToList();
In this example, we are selecting the order ID and date, along with the customer name and the total calculated from the order details.
Projections with extension methods
We can also combine Select
with other LINQ methods to perform more complex projections. For example:
var products = context.Products
.Where(p => p.Price > 100)
.Select(p => new
{
p.Name,
p.Price,
Category = p.Category.Name
})
.OrderBy(p => p.Price)
.ToList();
Here, we are filtering products with a price greater than 100, selecting the name, price, and category, and ordering the results by price.
Practical examples
Data projection for a view
Let’s say we are developing a web application and need to display a list of users with their name and email. We can use a projection to get only the necessary data:
var users = context.Users
.Select(u => new
{
u.Name,
u.Email
})
.ToList();
Projection with calculations
Imagine we need to calculate the total sales per customer. We can use a projection to perform this calculation directly in the query:
var salesPerCustomer = context.Orders
.GroupBy(o => o.Customer.Name)
.Select(g => new
{
Customer = g.Key,
TotalSales = g.Sum(o => o.Total)
})
.ToList();
Projection with related data
If we need to display a list of products along with their category, we can use a projection that includes data from a related entity:
var products = context.Products
.Select(p => new
{
p.Name,
p.Price,
Category = p.Category.Name
})
.ToList();