Skip to main content

NP0007: A mapper reads lazy navigations of each element by naming convention

Default severity: Info (a suggestion in the IDE; not shown in command-line builds unless raised)

What it detects​

An object mapper given EF entities (a whole result, or one element inside a loop) whose naming conventions read navigations the query did not include, while lazy loading is on:

var orders = await db.Orders.ToListAsync();
return orders.Adapt<List<OrderView>>(); // NP0007: OrderView.CustomerName flattens Customer.Name
return mapper.Map<List<LineView>>(lines); // NP0007 when no CreateMap<OrderLine, LineView> is visible

AutoMapper and Mapster both fill a destination member named like a navigation from it, and flatten names such as CustomerName from Customer.Name. Each navigation read that way on each element is one more query.

Why it is a suggestion​

The mapping configuration decides what is really read, and here it is not visible: the AutoMapper profile is in another project, or there is none and the mapper relies on its conventions. When an AutoMapper CreateMap<TSource, TDestination>() or a Mapster TypeAdapterConfig<TSource, TDestination>.NewConfig() (or config.NewConfig<TSource, TDestination>(), ForType) is in the same project, its overrides (AutoMapper's ForMember(..., o => o.MapFrom(...)) and Ignore(), Mapster's Map(d => d.X, s => ...) and Ignore(d => d.X)) are applied and the reads are reported as NP0002, a warning.

How to fix it​

Let the query build the destination, so it loads only what the view needs and nothing lazily:

var views = await db.Orders.ProjectTo<OrderView>(mapper.ConfigurationProvider).ToListAsync(); // AutoMapper
var views = await db.Orders.ProjectToType<OrderView>().ToListAsync(); // Mapster

or Include the navigations before mapping. Raise the rule to a warning once your mappings follow the conventions: dotnet_diagnostic.NP0007.severity = warning.