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 –

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
    public ProductCategory ProductCategory { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
    public string SKU { get; set; }
    public string Code { get; set; }
}  

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 –

1
2
3
4
5
6
public class ProductModel
{
    public int ProductId { get; set; }
    public string Name { get; set; }
    public string Code { get; set; }
}

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 –

1
2
3
SELECT TOP(@__p_0) [p].[ProductId], [p].[Code], [p].[Description], [p].[Name], [p].[Price], [p].[ProductCategory], [p].[SKU]
FROM [Products] AS [p]
ORDER 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 –

1
2
3
SELECT TOP(@__p_0) [p].[Code], [p].[Name], [p].[ProductId]
FROM [Products] AS [p]
ORDER 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.

1
2
3
4
5
6
7
public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Product, ProductModel>();
    }
}

In starup.cs add a call to Mapper.Initialize as shown here.

1
2
3
4
5
public void ConfigureServices(IServiceCollection services)
{
    Mapper.Initialize(cfg => {
        cfg.AddProfile<MappingProfile>();
    });

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.

comments powered by Disqus

Related