Skip to content

Troubleshooting

Practical problem/solution guide for Pragmatic.Mapping. Each section covers a common issue, the likely causes, and the fix.


You added [MapFrom<T>] or [MapTo<T>] but no FromEntity(), ToEntity(), or extension methods appear.

  1. Is the class partial? The SG cannot generate into a non-partial class. Diagnostic PRAG0300 is emitted if this is missing.

  2. Is the Pragmatic.SourceGenerator referenced as an analyzer? In your .csproj:

    <ProjectReference Include="..\Pragmatic.SourceGenerator\Pragmatic.SourceGenerator.csproj"
    OutputItemType="Analyzer"
    ReferenceOutputAssembly="false" />

    Without OutputItemType="Analyzer", the generator is treated as a normal reference and does not run.

  3. Is Pragmatic.Mapping referenced? The generator detects the mapping feature by looking for Pragmatic.Mapping.Attributes.MapFromAttribute in the compilation. Without the package reference, the feature is not activated.

  4. Rebuild the project. Source generators run during compilation. After adding the attribute, a full rebuild (dotnet build or Ctrl+Shift+B) is needed. IntelliSense may lag behind until the next build.

  5. Check the generated files. In Visual Studio, expand Dependencies > Analyzers > Pragmatic.SourceGenerator in Solution Explorer. The generated files should appear as {Type}.Mapping.g.cs and {Type}.Extensions.g.cs. On disk, they are in obj/Debug/net10.0/generated/.


FromEntity Returns Unexpected Default Values

Section titled “FromEntity Returns Unexpected Default Values”

The mapping runs, but some properties on the DTO are default(""), 0, or null instead of the expected values.

Property name mismatch. The DTO property name does not match any source property. The generator emits PRAG0303 for each unmatched property. Check the build warnings.

Navigation property not loaded. When using EF Core with FromEntity(), navigation properties must be explicitly loaded:

// Guest is null because it was not included
var reservation = await db.Reservations.FindAsync(id);
var dto = ReservationDto.FromEntity(reservation); // GuestFirstName = ""
// Fix: Include the navigation
var reservation = await db.Reservations
.Include(r => r.Guest)
.FirstOrDefaultAsync(r => r.PersistenceId == id);
// Or use Projection (recommended):
var dto = await db.Reservations
.Where(r => r.PersistenceId == id)
.Select(ReservationDto.Projection)
.FirstOrDefaultAsync();

Check ReservationDto.RequiredNavigations to see which navigations the DTO needs.

Converter property in projection. If the DTO has [GenerateProjection] and a property uses [MapConverter<T>], that property is excluded from the projection (PRAG0320) and gets default. Use FromEntity() instead, or restructure the DTO.

Format string in projection. Properties with [MapProperty(Format = "...")] are excluded from projections (PRAG0321) for the same reason.


The DTO has [GenerateProjection] but no Projection property appears.

  1. Does the DTO also have [MapFrom<T>]? [GenerateProjection] requires [MapFrom<T>] on the same type. Without it, diagnostic PRAG0310 is emitted and no projection is generated.

  2. Are all nested DTOs also decorated? If the DTO has a property of another DTO type, that nested DTO must also have [MapFrom<T>]. Missing it produces PRAG0309.

  3. Check for circular references. Circular DTO references are not supported in projections. The generator handles them in FromEntity() with instance tracking, but cannot express them in an Expression Tree.


The build fails with PRAG0304 (“Cannot map from ‘X’ to ‘Y’: incompatible types”).

The generator handles these conversions automatically:

DirectionTypes
To stringint, long, decimal, bool, Guid, DateTime, DateOnly, TimeOnly, enum
From stringint, long, decimal, bool, Guid, DateTime, DateOnly, TimeOnly, enum
Date conversionsDateTime to/from DateOnly, DateTime to TimeOnly
Implicit wideningint to long, int to decimal

If your conversion is not in this list, you need a custom converter:

public sealed class MyConverter : IValueConverter<SourceType, TargetType>
{
public TargetType Convert(SourceType source) => /* ... */;
public SourceType ConvertBack(TargetType target) => /* ... */;
}
// Apply to the property:
[MapProperty(nameof(Entity.SourceProp))]
[MapConverter<MyConverter>]
public TargetType TargetProp { get; init; }
DiagnosticCauseFix
PRAG0305Converter does not implement IValueConverter<TSource, TTarget>Implement the interface with the correct type parameters
PRAG0306Converter has no parameterless constructorAdd a public parameterless constructor

The DTO has a property whose type is another DTO, but that nested DTO does not have [MapFrom<T>].

// Fix: Add [MapFrom] to the nested DTO
[MapFrom<Address>]
public partial class AddressDto { /* ... */ }

The nested DTO has [MapFrom<X>] but the source navigation property is of type Y. The generic type argument must match the navigation property’s type.

PRAG0312: Nested projection type missing [GenerateProjection]

Section titled “PRAG0312: Nested projection type missing [GenerateProjection]”

When the parent DTO has [GenerateProjection] and a nested DTO property, the nested DTO must also support projection. The generator inlines the nested projection into the parent expression.


PRAG0323: “Property ‘X’ matches both direct property and convention, use [MapProperty] to be explicit.”

This occurs when a property matches both by direct name and by flattening convention. For example, if the entity has both Status and a navigation Status with further properties.

Fix: Add [MapProperty("Status")] or [MapProperty("Status.Name")] to clarify which source to use.


The build fails with PRAG03xx diagnostics from the source generator.

IDSeverityCauseFix
PRAG0300ErrorClass is not partialAdd partial keyword to the type declaration
PRAG0301ErrorSource type not foundVerify the generic type argument references an accessible type
PRAG0302ErrorProperty path not foundFix the path in [MapProperty("...")]
PRAG0303WarningNo matching source propertyFix property name, add [MapProperty], or add [MapIgnore]
PRAG0304ErrorIncompatible typesAdd [MapConverter<T>] or change the target type
PRAG0305ErrorConverter missing interfaceImplement IValueConverter<TSource, TTarget>
PRAG0306ErrorConverter missing constructorAdd a public parameterless constructor
PRAG0307WarningRequired target property not mapped ([MapTo])Add the property to the DTO or mark it optional on the entity
PRAG0309ErrorNested DTO missing [MapFrom]Add [MapFrom<T>] to the nested DTO type
PRAG0310Error[GenerateProjection] without [MapFrom]Add [MapFrom<T>] to the same type
PRAG0311WarningUntranslatable method in projectionAvoid non-SQL methods; use raw types
PRAG0312ErrorNested projection missing [GenerateProjection]Add [GenerateProjection] to nested DTO
PRAG0313InfoCircular reference detectedNo action needed; instance tracking is used
PRAG0314Error[MapIgnore] + [MapProperty] conflictRemove one of the two attributes
PRAG0315ErrorNested DTO type mismatchFix the [MapFrom<T>] type parameter on the nested DTO
PRAG0316ErrorNo suitable constructor for [MapTo]Add a parameterless constructor or use [MapConstructor]
PRAG0317ErrorNullable to non-nullable without defaultUse [MapProperty(Default = "...")] or change target to nullable
PRAG0319WarningCustomizeMapping ignored in projectionRemove CustomizeMapping or accept that it only runs in FromEntity
PRAG0320Warning[MapConverter] excluded from projectionUse raw type in projection DTO or accept default
PRAG0321InfoFormat string excluded from projectionUse raw type in projection DTO
PRAG0322InfoComplex dictionary not supportedUse [MapIgnore] on the dictionary property
PRAG0323WarningAmbiguous mapping matchAdd explicit [MapProperty] to resolve ambiguity
PRAG0324InfoID excluded from ToEntity()Add [MapProperty] to force inclusion, or accept the default

Check the Error List window in Visual Studio or the build output for diagnostic details and the affected source location.


Query returns all columns instead of projected subset

Section titled “Query returns all columns instead of projected subset”

Verify you are using Projection (Expression), not Selector (Func):

// Wrong: Selector is a Func -- EF Core evaluates client-side
db.Guests.Select(GuestDto.Selector).ToListAsync();
// Right: Projection is an Expression -- EF Core translates to SQL
db.Guests.Select(GuestDto.Projection).ToListAsync();

EF Core throws InvalidOperationException with “could not be translated” message. This means the expression contains a method call that EF Core’s SQL translator does not support. Check for:

  • Custom converters (should have been excluded with PRAG0320)
  • String methods that EF Core does not translate
  • Complex LINQ operations in nested collections

Solution: simplify the DTO to use only SQL-translatable property assignments.


The target entity does not have a constructor that the generator can use.

// Entity with no parameterless constructor:
public class User
{
public User(string email) { Email = email; }
public string Email { get; }
public string Name { get; init; } = "";
}
// Fix: Add [MapConstructor] to the preferred constructor
public class User
{
public User() { } // Or add parameterless
[MapConstructor]
public User(string email) { Email = email; }
public string Email { get; }
public string Name { get; init; } = "";
}

The generator’s constructor selection algorithm:

  1. Use the constructor marked with [MapConstructor]
  2. Use the parameterless constructor if available
  3. Use the best-match constructor (most parameters matched by DTO properties)

Yes. [MapFrom<T>] supports class, record, struct, and record struct. The type must be partial. [MapTo<T>] and [GenerateProjection] for structs are planned but not yet implemented.

No. All generated mapping code is static. No DI registration, no service injection, no startup configuration. Just reference the package and use the generated methods.

Not with multiple [MapFrom] attributes on the same class — this causes a compiler error (duplicate attribute). Create separate DTO types for each source type:

[MapFrom<Guest>]
public partial class GuestDto { /* ... */ }
[MapFrom<Employee>]
public partial class EmployeeDto { /* ... */ }

What happens to properties that exist on the DTO but not the entity?

Section titled “What happens to properties that exist on the DTO but not the entity?”

They receive default (e.g., "" for string, 0 for int, null for nullable types) and the generator emits PRAG0303. Use [MapIgnore] to suppress the warning for intentionally unmapped properties like computed fields.

Yes. The generated files are in obj/Debug/net10.0/generated/Pragmatic.SourceGenerator/. You can open them in your IDE and set breakpoints. In Visual Studio, they are also visible under Dependencies > Analyzers > Pragmatic.SourceGenerator.

The generator maps inherited properties from base classes automatically. If Guest inherits from BaseEntity which has Id and CreatedAt, those properties are available for mapping on [MapFrom<Guest>] DTOs.