Search code examples
c#entity-framework-coremappingautomapperblazor-server-side

AutoMapper: What is the difference between CreateMap and CreateProjection?


I am looking for an explanation of the difference between CreateMap/CreateProjection in automapper and ProjectTo/MapTo by relation. I just got started with the library and I am having trouble understanding what to use when. I partially understand that ProjectTo has some relation to LINQ and can be used for entire collections? I wish to use this library in a Blazor Server Side project.

I am also looking into these two libraries as I am using EF Core:

But as I am new to the library I think it is a good idea to start with the base first before moving on.


Solution

  • TL;DR

    If you don’t use Map, just ProjectTo, you should use CreateProjection instead of CreateMap. That way you’ll use only the API subset supported by ProjectTo and start-up should be faster.

    CreateProjection explicitly disables Map. CreateMap allows both.

    So if you need only entity -> DTO mapping via ORM (like Entity Framework) and ProjectTo then use CreateProjection, otherwise use CreateMap.

    Details

    As written in the docs if you are working with ORM based on IQueryable you can use ProjectTo so the AutoMapper+ORM pair can generate a proper SQL statement instead of fetching the whole entity into memory (if your are not mapping in one-to-one fashion this can have positive effect on performance) and mapping it client side:

    var configuration = new MapperConfiguration(cfg =>
        cfg.CreateProjection<OrderLine, OrderLineDTO>()
        .ForMember(dto => dto.Item, conf => conf.MapFrom(ol => ol.Item.Name)));
    
    public List<OrderLineDTO> GetLinesForOrder(int orderId)
    {
      using (var context = new orderEntities())
      {
        return context.OrderLines.Where(ol => ol.OrderId == orderId)
                 .ProjectTo<OrderLineDTO>(configuration).ToList();
      }
    }
    

    The .ProjectTo<OrderLineDTO>() will tell AutoMapper’s mapping engine to emit a select clause to the IQueryable that will inform entity framework that it only needs to query the Name column of the Item table, same as if you manually projected your IQueryable to an OrderLineDTO with a Select clause.

    Due to the nature of the ProjectTo it is much more limited in what it can actually map/do (not everything can be turned into SQL).

    Read more:

    1. What is the difference between IQueryable and IEnumerable?
    2. Defining both CreateProjection and CreateMap

      CreateProjection explicitly disables Map. CreateMap allows both.

    3. 11.0 Upgrade Guide:

      If you don’t use Map, just ProjectTo, you should use CreateProjection instead of CreateMap. That way you’ll use only the API subset supported by ProjectTo and start-up should be faster.

    4. 12.0 Upgrade Guide

      You also cannot have for the same map/member separate configurations for Map and ProjectTo.

    5. AutoMapper ConvertUsing is not called