AutoMapper, ProjectTo() – Static Version
Full source code available here.
I’ve been using AutoMapper for quite a few years, but one of the features that I like the most is the ProjectTo
method. When using Entity Framework it lets me reduce the number of fields I query from the database to match the model I want to return to the caller.
For example, I have a Product table in the database and a DTO that represents the Product that looks like this –
1public class Product
2{
3 public int ProductId { get; set; }
4 public string Name { get; set; }
5 public ProductCategory ProductCategory { get; set; }
6 public string Description { get; set; }
7 public decimal Price { get; set; }
8 public string SKU { get; set; }
9 public string Code { get; set; }
10}
But say I wanted to return only the ProductId
, Name
and Code
, I could run a query to return the full Product
and the map the results to a model that looks like this –
1public class ProductModel
2{
3 public int ProductId { get; set; }
4 public string Name { get; set; }
5 public string Code { get; set; }
6}
In this scenario, the generated SELECT
statement will request all seven fields in product and return them to the application, I then have to them to the ProductModel
with the three fields I want.
Here is the SQL produced an executed –
1SELECT TOP(@__p_0) [p].[ProductId], [p].[Code], [p].[Description], [p].[Name], [p].[Price], [p].[ProductCategory], [p].[SKU]
2FROM [Products] AS [p]
3ORDER BY [p].[ProductId]
Instead of requesting all seven fields the ProjectTo
method will examine the model and generate only the SQL needed to return the relevant fields.
Here is the SQL produced –
1SELECT TOP(@__p_0) [p].[Code], [p].[Name], [p].[ProductId]
2FROM [Products] AS [p]
3ORDER BY [p].[ProductId]
And here is how to write the C# code that performs this time saving, energy saving work –
var productModels = _salesContext.Products.OrderBy(p => p.ProductId).Take(count).ProjectTo<ProductModel>();
To get this to work you need to do some wiring up.
First add the nuget package AutoMapper.Extensions.Microsoft.DependencyInjection v6.1.1
to your project.
Then create a mapping profile, for this scenario it is very simple. The below code maps Product
to ProductModel
.
1public class MappingProfile : Profile
2{
3 public MappingProfile()
4 {
5 CreateMap<Product, ProductModel>();
6 }
7}
In starup.cs
add a call to Mapper.Initialize
as shown here.
1public void ConfigureServices(IServiceCollection services)
2{
3 Mapper.Initialize(cfg => {
4 cfg.AddProfile<MappingProfile>();
5 });
That’s all you need, but that’s not the end of the story…
This approach works with AutoMapper.Extensions.Microsoft.DependencyInjection up to v6.1.1, and AutoMapper v8.1.1, but if you move to newer versions you need a slightly different approach because the static API has been removed.
I’ll show that in the next blog post.
Full source code available here.