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 –
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 –
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 –
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 –
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.
public class MappingProfile : Profile { public MappingProfile() { CreateMap<Product, ProductModel>(); } }
In starup.cs
add a call to Mapper.Initialize
as shown here.
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.