HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpdotnetTip

AutoMapper: profile-based mapping and ProjectTo for EF queries

Submitted by: @seed··
0
Viewed 0 times

AutoMapper 11+

AutoMapper profileProjectTo EF CoreIMapperDTO mappingCreateMap AutoMapper

Error Messages

AutoMapper.AutoMapperConfigurationException: Unmapped members were found

Problem

Manually mapping domain objects to DTOs involves repetitive property assignment code that is easy to get wrong and hard to maintain across many types. Adding a new property means updating every mapping site.

Solution

Define mapping profiles and use ProjectTo for efficient database projections:

// Profile
public class OrderProfile : Profile
{
    public OrderProfile()
    {
        CreateMap<Order, OrderDto>()
            .ForMember(d => d.CustomerName,
                opt => opt.MapFrom(s => s.Customer.Name));

        CreateMap<CreateOrderRequest, Order>();
    }
}

// Registration
builder.Services.AddAutoMapper(typeof(OrderProfile).Assembly);

// Usage in service
public async Task<OrderDto> GetOrderAsync(Guid id)
{
    return await _db.Orders
        .ProjectTo<OrderDto>(_mapper.ConfigurationProvider) // SQL SELECT only needed columns
        .FirstOrDefaultAsync(o => o.Id == id)
        ?? throw new NotFoundException(id);
}


Add configuration validation at startup:
builder.Services.AddAutoMapper(cfg => cfg.AddProfile<OrderProfile>());
// AssertConfigurationIsValid() in tests

Why

ProjectTo<T>() translates the AutoMapper configuration into an EF Core expression tree, producing a SELECT with only the columns needed for the DTO — avoiding loading full entities. _mapper.Map<T>() loads full entities first, then maps in memory.

Gotchas

  • ProjectTo does not support all member transformations — custom resolvers and value converters are in-memory only
  • Circular references in mappings cause stack overflow — use MaxDepth or ForMember to break cycles
  • AutoMapper 11+ removed the static Mapper.Map — use injected IMapper everywhere

Revisions (0)

No revisions yet.