Skip to content

Attributes Reference

The complete reference for every Pragmatic.Mapping attribute, the property-matching rules the generator follows, the customization hooks it emits, the EF Core query helpers, the mutation helpers, and the diagnostics. For the mental model and a guided first mapping, start with Concepts and Getting Started.

Generates mapping from a source type (typically an entity) to the decorated DTO.

Generated members:

  • static TDto FromEntity(TSource entity) — static factory method
  • static Func<TSource, TDto> Selector — delegate for in-memory LINQ
  • Extension methods: entity.ToDto(), IEnumerable<T>.ToDto(), List<T>.ToDto(), T[].ToDto()

Usage:

[MapFrom<User>]
public partial class UserDto
{
public Guid Id { get; init; }
public string Name { get; init; } = "";
}

Requirements: The type must be declared as partial. Supports class, record, struct, and record struct.

Generates mapping from the DTO to a target type (typically an entity).

Generated members:

  • TTarget ToEntity() — creates a new entity instance
  • void ApplyTo(TTarget entity) — updates an existing entity (partial update semantics for nullable properties)

Usage:

[MapTo<User>]
public partial record CreateUserDto
{
public string Email { get; init; } = "";
public string FirstName { get; init; } = "";
}
// Creates a new entity
User user = dto.ToEntity();
// Updates an existing entity
dto.ApplyTo(existingUser);

Note: ID properties (Id, {EntityName}Id) are excluded from ToEntity() by default. Use [MapProperty] on the ID property to force inclusion.

Generates Expression<Func<TSource, TDto>> Projection for EF Core Select() queries. Requires [MapFrom<T>] on the same type.

Projections translate to SQL, so only SQL-translatable operations are supported. Converters ([MapConverter]), format strings, and CustomizeMapping() are excluded from projections with compile-time warnings.

Usage:

[MapFrom<Property>]
[GenerateProjection]
public partial class PropertySummaryDto
{
public Guid Id { get; init; }
public string Name { get; init; } = "";
public string City { get; init; } = "";
public int StarRating { get; init; }
}
// SQL-optimized query
var dtos = await db.Properties
.Where(p => p.IsActive)
.Select(PropertySummaryDto.Projection)
.ToListAsync();

See Projections for details.

Generates an additional FromEntityBodyOnly() method that maps only scalar properties, skipping collections, nested DTOs, and dictionaries. Useful for mutation scenarios.

[MapFrom<Reservation>]
[GenerateBodyOnlyVariant]
public partial class ReservationSummaryDto
{
public Guid Id { get; init; }
public decimal TotalAmount { get; init; } // Mapped in both
public ReservationStatus Status { get; init; } // Mapped in both
[MapProperty("Guest.FirstName")]
public string GuestFirstName { get; init; } = ""; // Skipped in BodyOnly
}

Customizes how a single property is mapped.

Capabilities:

FeatureSyntaxExample
Explicit source path[MapProperty("Address.City")]Flatten navigation
Concatenation[MapProperty("FirstName", "LastName")]Multiple paths joined
Custom separatorSeparator = ", ""Doe, John"
Format stringFormat = "yyyy-MM-dd"Date formatting via .ToString(format)
Default valueDefault = "N/A"Fallback for nullable to non-nullable
Target path (MapTo)Target = "Customer.Name"Map to nested entity property

Examples from Showcase:

// Navigation flattening (Showcase: RoomTypeSummaryDto)
[MapProperty("Property.Name")]
public string PropertyName { get; init; } = "";
// Format string (Showcase: PropertyDetailDto)
[MapProperty("CreatedAt", Format = "yyyy-MM-dd")]
public string CreatedDate { get; init; } = "";
// Concatenation
[MapProperty(nameof(User.FirstName), nameof(User.LastName))]
public string FullName { get; init; } = "";
// Default value for nullable source
[MapProperty(nameof(User.MiddleName), Default = "N/A")]
public string MiddleName { get; init; } = "";

Excludes a property from mapping. Use for computed properties or properties populated elsewhere.

[MapFrom<Guest>]
public partial class GuestDto
{
public string FirstName { get; init; } = "";
public string LastName { get; init; } = "";
[MapIgnore]
public string FullName => $"{FirstName} {LastName}";
}

Specifies a custom IValueConverter<TSource, TTarget> for a property. The converter must have a parameterless constructor.

Not supported in projections (PRAG0320 warning) — converters cannot be translated to SQL.

// 1. Implement IValueConverter
public sealed class MoneyToStringConverter : IValueConverter<decimal, string>
{
public string Convert(decimal source) => source.ToString("N2");
public decimal ConvertBack(string target) =>
decimal.TryParse(target, out var result) ? result : 0m;
}
// 2. Use on a property (Showcase: InvoiceSummaryDto)
[MapFrom<Invoice>]
public partial class InvoiceSummaryDto
{
[MapProperty(nameof(Invoice.TotalAmount))]
[MapConverter<MoneyToStringConverter>]
public string TotalFormatted { get; init; } = "";
}

See Custom Converters for the full guide.

Forces the generator to use a specific constructor when creating entity instances in [MapTo] scenarios. When omitted, the generator uses a best-match algorithm.

public class User
{
public User() { }
[MapConstructor]
public User(int id, string email) { Id = id; Email = email; }
}

The generator resolves DTO properties to source properties in this order:

PriorityStrategyExample
1[MapProperty] explicit path[MapProperty("Address.City")] on City
2[MapConverter<T>]Custom type conversion
3Direct name match (case-insensitive)Name maps to Name
4Flattening conventionAddressCity maps to Address.City
5Concatenation conventionFullName maps to FirstName + " " + LastName

Unmatched properties generate a PRAG0303 warning and receive default.

When the source is nullable and the target is not, the generator applies sensible defaults: string? to string uses ?? "", numeric/bool/date/Guid types use .GetValueOrDefault(), enums use .GetValueOrDefault(). For explicit control, use [MapProperty(Default = "value")].

The generator detects type mismatches and applies conversions automatically. Supported conversions include: numeric/enum/Guid/bool/DateTime to/from string (via .ToString() / .Parse()), DateTime to/from DateOnly and TimeOnly, and implicit widening (int to long). See Feature Matrix for the full table.

Collections (List<T>, T[], IEnumerable<T>, HashSet<T>, Dictionary<K,V>) are mapped element-by-element. Cross-collection type conversions (List<T> to T[] and vice versa) are supported.

When a DTO property is itself a DTO with [MapFrom<T>], the generator calls FromEntity() recursively. Circular references are detected at compile time (PRAG0313 info) and handled with instance tracking.

The generator emits two partial methods that you can implement:

[MapFrom<User>]
public partial class UserDto
{
public Guid Id { get; init; }
public string Name { get; init; } = "";
// Called BEFORE mapping. Return a result to short-circuit.
static partial void BeforeMapping(User source, ref UserDto? result)
{
if (source.IsDeleted)
{
result = new UserDto { Name = "[Deleted]" };
// Mapping stops here
}
}
// Called AFTER mapping. Modify the context to adjust values.
static partial void CustomizeMapping(User source, ref UserDtoMappingContext ctx)
{
ctx.Name = ctx.Name.ToUpperInvariant();
}
}

The generator creates a {TypeName}MappingContext struct with mutable fields for each mapped property. CustomizeMapping receives this struct by ref, allowing you to modify any mapped value before the final DTO is constructed.

Note: CustomizeMapping is ignored in [GenerateProjection] (PRAG0319 warning) because Expression Trees cannot contain arbitrary C# logic.

EF Core query helpers (Pragmatic.Mapping.EFCore)

Section titled “EF Core query helpers (Pragmatic.Mapping.EFCore)”

The Pragmatic.Mapping.EFCore package provides extension methods for IQueryable<T> that work with generated projections:

MethodDescription
SelectDto(projection)Projects query using expression
ToListDtoAsync(projection)Async projection to list
FirstOrDefaultDtoAsync(projection)Async single item projection
SingleOrDefaultDtoAsync(projection)Async single-or-default projection
ToArrayDtoAsync(projection)Async projection to array
ToPagedDtoAsync(projection, page, size)Paginated projection with metadata
ToSliceDtoAsync(projection, offset, limit)Offset/limit projection

All methods include OpenTelemetry ActivitySource tracing with Pragmatic.Mapping activity names.

// Paginated results
var page = await db.Properties
.Where(p => p.IsActive)
.OrderBy(p => p.Name)
.ToPagedDtoAsync(PropertySummaryDto.Projection, pageNumber: 1, pageSize: 20);
page.Items // IReadOnlyList<PropertySummaryDto>
page.TotalCount // Total matching items
page.TotalPages // Computed page count
page.HasNextPage // Pagination flag

The Include problem: FromEntity() operates on in-memory objects — navigation properties not loaded via .Include() will be null, producing silent data loss. Prefer Projection for EF Core queries, or use explicit .Include(). See Common Mistakes.

MutationHelpers provides composable methods for applying DTO changes to entities:

  • MapOneToOne — Maps a 1:1 reference navigation. If the DTO value is null, the navigation is set to null. Otherwise updates in-place or creates new.
  • MapOneToMany — Synchronizes a collection navigation with three strategies:
    • CollectionStrategy.Sync — Add new, update existing, remove missing (default)
    • CollectionStrategy.AddOnly — Add new, update existing, never remove
    • CollectionStrategy.Replace — Clear all and recreate from DTO
MutationHelpers.MapOneToOne(
dto.ShippingAddress,
() => order.ShippingAddress,
addr => order.ShippingAddress = addr,
addrDto => addrDto.ToEntity(),
(addrDto, addr) => addrDto.ApplyTo(addr));
MutationHelpers.MapOneToMany(
dto.Lines, order.Lines,
d => d.Id, e => e.Id,
lineDto => lineDto.ToEntity(),
(lineDto, line) => lineDto.ApplyTo(line),
CollectionStrategy.Sync);
IDSeverityDescription
PRAG0300ErrorType must be declared as partial
PRAG0303WarningNo matching source property (will use default)
PRAG0307WarningRequired property not mapped in [MapTo]
PRAG0309ErrorNested type missing [MapFrom]
PRAG0313InfoCircular reference detected, using instance tracking
PRAG0316ErrorNo suitable [MapTo] constructor (required parameter has no matching property)
PRAG0319WarningCustomizeMapping ignored in Projection
PRAG0320Warning[MapConverter] not supported in Projection
PRAG0321WarningFormat string not translatable to SQL
PRAG0322WarningComplex dictionary value not supported
PRAG0324InfoID property excluded from ToEntity()