patterncsharpdotnetTip
AutoMapper: profile-based mapping and ProjectTo for EF queries
Viewed 0 times
AutoMapper 11+
AutoMapper profileProjectTo EF CoreIMapperDTO mappingCreateMap AutoMapper
Error Messages
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:
Add configuration validation at startup:
// 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 testsWhy
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.