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.

comments powered by Disqus

Related