Skip to content

Pragmatic.Mapping - Feature Matrix

Documento per tracciare le funzionalità implementate e testate. Ogni casella rappresenta una combinazione che DEVE essere supportata e testata.

Last Updated: 2026-01-02 Test Summary: 125 passing, 0 failing


SymbolMeaning
Implemented & Tested
⚠️Implemented, needs fix
Not implemented
🔲Planned

Type KindFromEntityToEntityProjectionTest File
classNullableAndNestedGeneratorTests.PartialClass_GeneratesCorrectly
recordBasicMappingGeneratorTests
struct🔲🔲NullableAndNestedGeneratorTests.PartialStruct_GeneratesCorrectly
record struct🔲🔲BasicMappingGeneratorTests.MapFrom_RecordStruct_GeneratesCorrectly

Source Type KindSupportTest
classAll basic tests
record-
structNullableAndNestedGeneratorTests.PartialStruct_GeneratesCorrectly
record struct-

Note: Null check skipped for value types (structs can’t be null).


TypeDirect MappingTest
intBasicMappingGeneratorTests
int?NullableAndNestedGeneratorTests.NullableInt_MapsDirectly
stringMultiple tests
string?NullableAndNestedGeneratorTests.NullableString_MapsDirectly
decimalNullableAndNestedGeneratorTests.PartialClass_GeneratesCorrectly
DateTime-
DateTime?NullableAndNestedGeneratorTests.NullableDateTime_MapsDirectly
Guid-
Guid?TypeConversionGeneratorTests.NullableGuid_MapsDirectly
DateOnlyTypeConversionGeneratorTests.DateOnly_MapsDirectly
TimeOnlyTypeConversionGeneratorTests.DateOnly_MapsDirectly
DateOnly?TypeConversionGeneratorTests.NullableDateOnly_MapsDirectly
TimeOnly?TypeConversionGeneratorTests.NullableDateOnly_MapsDirectly
enumTypeConversionGeneratorTests.Enum_SameType_MapsDirectly
enum?TypeConversionGeneratorTests.NullableEnum_MapsDirectly
Collection TypeSimple ElementDTO ElementTest
T[]CollectionMappingGeneratorTests.ArrayOfInt, ArrayOfDto
List<T>CollectionMappingGeneratorTests.ListOfString, ListOfDto
List<T>?NullableListOfNullableInt, NullableListOfNullableNestedDto
IList<T>CollectionMappingGeneratorTests.IListOfInt
ICollection<T>CollectionMappingGeneratorTests.ICollectionOfInt
IEnumerable<T>CollectionMappingGeneratorTests.IEnumerableOfInt
IReadOnlyList<T>🔲CollectionMappingGeneratorTests.IReadOnlyListOfInt
IReadOnlyCollection<T>🔲CollectionMappingGeneratorTests.IReadOnlyCollectionOfInt
HashSet<T>🔲CollectionMappingGeneratorTests.HashSetOfInt
ScenarioStatusTest
Single non-nullable DTONullableAndNestedGeneratorTests.NestedDto_MapsWithFromEntity
Single nullable DTONullableAndNestedGeneratorTests.NullableNestedDto_HandlesNullSafely
Array of DTONullableAndNestedGeneratorTests.ArrayOfNestedDto_MapsEachElement
List of DTOCollectionMappingGeneratorTests.ListOfDto_MapsEachElement
List of nullable DTONullableAndNestedGeneratorTests.NullableListOfNullableNestedDto_HandlesCorrectly

Implementation: Uses SymbolDisplayFormat.FullyQualifiedFormat for type names to avoid namespace resolution issues.

Dictionary TypeSimple ValueDTO ValueTest
Dictionary<K,V>CollectionMappingGeneratorTests.DictionaryStringInt, TypeConversionGeneratorTests.DictionaryWithDtoValue
IDictionary<K,V>🔲🔲-
IReadOnlyDictionary<K,V>🔲🔲-
ConversionStatusTest
intlongTypeConversionGeneratorTests.IntToLong_ImplicitConversion
intdecimalTypeConversionGeneratorTests.IntToDecimal_ImplicitConversion
int?int (no default)⚠️ CS0266TypeConversionGeneratorTests.NullableIntToInt_WithoutDefault_ShouldCompile
int?int (with default)AdvancedMappingGeneratorTests.MapProperty_WithDefault_UsesDefaultWhenNull

Note: C# implicit conversions (widening) work automatically. Nullable → Non-nullable requires [MapProperty(Default=)].

3.6 Type Conversions (Explicit) ✅ IMPLEMENTED

Section titled “3.6 Type Conversions (Explicit) ✅ IMPLEMENTED”
ConversionStatusGenerated CodeTest
intstring.ToString()TypeConversionGeneratorTests.IntToString
stringintint.Parse()TypeConversionGeneratorTests.StringToInt
enumstring.ToString()TypeConversionGeneratorTests.EnumToString
stringenumEnum.Parse<T>()TypeConversionGeneratorTests.StringToEnum
Guidstring.ToString()TypeConversionGeneratorTests.GuidToString
stringGuidGuid.Parse()TypeConversionGeneratorTests.StringToGuid
DateTimeDateOnlyDateOnly.FromDateTime()TypeConversionGeneratorTests.DateTimeToDateOnly
DateOnlyDateTime.ToDateTime(TimeOnly.MinValue)TypeConversionGeneratorTests.DateOnlyToDateTime
DateTimeTimeOnlyTimeOnly.FromDateTime()TypeConversionGeneratorTests.DateTimeToTimeOnly
decimalstring.ToString()TypeConversionGeneratorTests.DecimalToString
stringdecimaldecimal.Parse()TypeConversionGeneratorTests.StringToDecimal
boolstring.ToString()TypeConversionGeneratorTests.BoolToString
stringboolbool.Parse()TypeConversionGeneratorTests.StringToBool
DateTimestring.ToString()TypeConversionGeneratorTests.DateTimeToString
stringDateTimeDateTime.Parse()TypeConversionGeneratorTests.StringToDateTime
stringDateOnlyDateOnly.Parse()TypeConversionGeneratorTests.StringToDateOnly
stringTimeOnlyTimeOnly.Parse()TypeConversionGeneratorTests.StringToTimeOnly

Implementation: Generator detects source/target type mismatch and applies known conversion patterns automatically. Nullable variants also supported (e.g., int?string, stringint?).

Source → TargetStatusTest
List<T>T[]TypeConversionGeneratorTests.ListToArray_Conversion
T[]List<T>TypeConversionGeneratorTests.ArrayToList_Conversion
IEnumerable<T>List<T>TypeConversionGeneratorTests.IEnumerableToList_Conversion
List<T>IEnumerable<T>TypeConversionGeneratorTests.ListToIEnumerable_Conversion
List<T>HashSet<T>TypeConversionGeneratorTests.ListToHashSet_Conversion
T[]IReadOnlyList<T>TypeConversionGeneratorTests.ArrayToIReadOnlyList_Conversion

AttributeStatusTest
[MapFrom<T>]All FromEntity tests
[MapTo<T>]AdvancedMappingGeneratorTests.MapTo_*
[MapProperty]AdvancedMappingGeneratorTests.MapProperty_*
[MapProperty(Default=)]AdvancedMappingGeneratorTests.MapProperty_WithDefault_UsesDefaultWhenNull
[MapIgnore]AdvancedMappingGeneratorTests.MapIgnore_*
[MapConverter<T>]AdvancedMappingGeneratorTests.Converter_*
[MapConstructor]AdvancedMappingGeneratorTests.MapTo_UsesConstructor
[GenerateProjection]ProjectionGeneratorTests.*

StrategyStatusTest
Direct name matchAll basic tests
Case-insensitive match-
Flattening (AddressCityAddress.City)AdvancedMappingGeneratorTests.Flattening_*
Concatenation (FullNameFirstName + LastName)BasicMappingGeneratorTests.MapFrom_WithFullNameConvention
Explicit path via [MapProperty]AdvancedMappingGeneratorTests.MapProperty_*
FeatureStatusTest
ID property exclusion in ToEntityAdvancedMappingGeneratorTests.MapTo_ExcludesIdByDefault
Init-only properties-
Required properties-
Circular reference detection-
Null safetyNullableAndNestedGeneratorTests.*
MethodStatusStruct SupportTest
FromEntity(entity)All FromEntity tests
ToEntity()🔲MapTo tests
Projection🔲ProjectionGeneratorTests

Note: ApplyTo() functionality moved to Pragmatic.Domain as [Mutation<T>] attribute.

HookStatusTest
partial void BeforeMapping()-
partial void CustomizeMapping()-
MappingContext struct-

DTO AccessibilitySupportExtensions ClassTest
publicpublic staticAll basic tests
internalinternal staticAdvancedMappingGeneratorTests.MapFrom_InternalClass_GeneratesInternalMethods
private (nested)🔲--

BugStatusFix
Struct source + Ensure.ThrowIfNull✅ FIXEDSkip null check for value types
Nullable DTO type name includes ?✅ FIXEDUse SymbolDisplayFormat.FullyQualifiedFormat
List<string> treated as DTO collection✅ FIXEDCheck IsElementSimple in AnalyzeNestedDto
Extensions class ignores accessibility✅ FIXEDAdded ParseAccessibility() in MappingExtensionsTemplate
[MapProperty(Default=)] not implemented✅ FIXEDAdded fallback resolution by property name when only Default is specified
IssueStatusFixTest
[MapProperty(Format=)] for non-DateTime✅ FIXEDAdded format support to GenerateNumericToString and GenerateToStringAdvancedMappingGeneratorTests.MapProperty_WithFormat_*
[MapProperty] + [MapConverter] together✅ FIXEDMoved converter check before MapProperty check, passed converter to CreateExplicitMappingAdvancedMappingGeneratorTests.MapProperty_WithMapConverter_*

Test FileTestsPassingFailing
BasicMappingGeneratorTests770
AdvancedMappingGeneratorTests16160
CollectionMappingGeneratorTests990
ProjectionGeneratorTests550
NullableAndNestedGeneratorTests990
TypeConversionGeneratorTests51510
AutomaticConversionGeneratorTests12120
AutoDefaultGeneratorTests12120
DiagnosticTests440
TOTAL1251250

Note: EF Core integration tests use TestContainers with PostgreSQL.


Sample FileFeatures Demonstrated
BasicMappingSampleFromEntity, extension methods, collection mapping, FullName concatenation, flattening
NestedMappingSampleNested DTOs, collection of DTOs, flattened DTO
BidirectionalMappingSampleMapFrom + MapTo, ToEntity()
StructMappingSamplerecord struct, zero-allocation, Projection
ProjectionSampleGenerateProjection, Expression<Func<T,TDto>>
TypeConversionSampleToString, Parse, DateTime↔DateOnly, Dictionary with DTOs, Inheritance
NullableAndAdvancedSampleAuto-default, Collection type conversions, Circular references, DateOnly→DateTime
TypeCombinationsSampleclass→class, class→record, record→record, record→class, MapIgnore
AdvancedAttributesSampleMapIgnore, MapConverter, MapProperty(path), MapProperty(Format)

  • Core source generator (FromEntity, ToEntity, Projection)
  • All property types (simple, nullable, collections, nested DTOs)
  • Property resolution (direct match, flattening, concatenation)
  • MapProperty with Default value
  • MapIgnore, MapConverter attributes
  • EF Core integration package with extension methods
  • Comprehensive samples (Basic, Nested, Bidirectional, Struct, Projection, TypeConversion)
  • README documentation
  • P0: Auto-default for primitives (GetValueOrDefault, ?? "")
  • P1: Type conversions (ToString, Parse, enum↔string, Guid↔string)
  • P2: DateTime conversions (DateTime↔DateOnly/TimeOnly)
  • P3: Dictionary with DTO values, Inheritance mapping

P0 - Critical (MVP completeness) ✅ COMPLETE

Section titled “P0 - Critical (MVP completeness) ✅ COMPLETE”
FeatureDescriptionStatus
Auto-default for primitivesint?int uses GetValueOrDefault(), string?string uses ?? ""✅ Implemented
Auto-default in ProjectionUses ?? 0, ?? "", ?? Guid.Empty for EF Core Expression Tree compatibility✅ Implemented
FeatureDescriptionStatusTest
ToString conversionsintstring via .ToString()TypeConversionGeneratorTests.IntToString
Enum → stringStatus.Active"Active"TypeConversionGeneratorTests.EnumToString
Parse conversionsstringint via int.Parse()TypeConversionGeneratorTests.StringToInt
Guid ↔ stringGuid.ToString() / Guid.Parse()TypeConversionGeneratorTests.GuidToString/StringToGuid
FeatureDescriptionStatusTest
DateTime → DateOnlyDateOnly.FromDateTime()TypeConversionGeneratorTests.DateTimeToDateOnly
DateTime → TimeOnlyTimeOnly.FromDateTime()TypeConversionGeneratorTests.DateTimeToTimeOnly
DateOnly → DateTime.ToDateTime(TimeOnly.MinValue)TypeConversionGeneratorTests.DateOnlyToDateTime
String ↔ decimalParse/ToStringTypeConversionGeneratorTests.StringToDecimal/DecimalToString
FeatureDescriptionStatusTest
Dictionary with DTO valuesDictionary<string, CategoryDto>TypeConversionGeneratorTests.DictionaryWithDtoValue
Inheritance mappingBase → Derived DTO propertiesTypeConversionGeneratorTests.InheritedProperties
Interface-based DTOsIUserDto🔲Future

ScenarioCategoryTest FileStatus
Same-name property mappingBasicBasicMappingGeneratorTests
Different-name property mappingAdvancedAdvancedMappingGeneratorTests
Custom converterAdvancedAdvancedMappingGeneratorTests
Nested DTO mappingNestedNullableAndNestedGeneratorTests
Collection of DTOsCollectionCollectionMappingGeneratorTests
ScenarioTestStatus
Non-partial class skips generationDiagnosticTests.NonPartialClass_SkipsGeneration
Partial class generates correctlyDiagnosticTests.PartialClass_GeneratesCorrectly
Unmatched property uses defaultDiagnosticTests.UnmatchedProperty_GeneratesWithDefault
Invalid MapProperty pathDiagnosticTests.MapProperty_WithInvalidPath_CompilesButUnmapped
[GenerateProjection] without [MapFrom]DiagnosticTests.GenerateProjection_WithoutMapFrom_SkipsProjection
[MapIgnore] takes precedenceDiagnosticTests.MapIgnore_TakesPrecedence_OverMapProperty
Nested DTO with [MapFrom]DiagnosticTests.NestedDto_WithMapFrom_GeneratesCorrectly
Collection with simple elementsDiagnosticTests.Collection_WithSimpleElements_MapsDirectly
Struct source skips null checkDiagnosticTests.StructSource_SkipsNullCheck
Class source includes null checkDiagnosticTests.ClassSource_IncludesNullCheck
MapTo excludes ID by defaultDiagnosticTests.MapTo_ExcludesIdByDefault
Internal class generates internal extensionsDiagnosticTests.InternalClass_GeneratesInternalExtensions
Empty DTO generates minimalDiagnosticTests.EmptyDto_GeneratesMinimalMapping
Multiple [MapFrom] causes errorDiagnosticTests.MultipleMapFrom_CausesDuplicateAttributeError
Bidirectional mappingDiagnosticTests.MapFrom_And_MapTo_OnSameType_GeneratesBothMethods

  • [MapProperty(Default = "value")] per default values
  • Flattening convention (Address.CityAddressCity)
  • Concatenation convention (FullNameFirstName + LastName)
  • EF Core projection expressions
  • Auto-default for primitives (int?int = GetValueOrDefault())
  • Auto-default for strings (string?string = ?? "")
  • Auto-default in Projections (EF Core compatible with ?? value)
  • Type conversions (ToString, Parse, enum↔string, Guid↔string)
  • DateTime conversions (DateTime↔DateOnly, DateTime↔TimeOnly)
  • Dictionary with DTO values (Dictionary<string, CategoryDto>)
  • Inheritance mapping (base class properties mapped automatically)
  • Custom projection expressions
  • Async mapping per lazy loading
  • Interface-based DTOs

When using EF Core, navigation properties require explicit Include() calls when using FromEntity():

// ⚠️ PROBLEM: Lazy loading or null navigation properties
var users = await _db.Users.ToListAsync();
var dtos = users.ToUserDto(); // Orders will be null/empty!
// ✅ SOLUTION 1: Manual Include
var users = await _db.Users
.Include(u => u.Orders)
.ToListAsync();
var dtos = users.ToUserDto();
// ✅ SOLUTION 2: Use Projection (BEST - optimized SQL)
var dtos = await _db.Users
.Select(UserDto.Projection)
.ToListAsync();

Implemented Features (Pragmatic.Mapping.EntityFrameworkCore)

Section titled “Implemented Features (Pragmatic.Mapping.EntityFrameworkCore)”
FeatureStatusDescription
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
// Projection-based (generates optimized SQL)
var dtos = await _db.Users
.Where(u => u.IsActive)
.ToListDtoAsync(UserDto.Projection);
// Paginated results
var page = await _db.Users
.Where(u => u.IsActive)
.OrderBy(u => u.Name)
.ToPagedDtoAsync(UserDto.Projection, pageNumber: 1, pageSize: 20);
// page.Items, page.TotalCount, page.TotalPages, page.HasNextPage, etc.

Future Features (Pragmatic.Mapping.DomainEntity)

Section titled “Future Features (Pragmatic.Mapping.DomainEntity)”
FeatureStatusDescription
RequiredIncludes<TDto>()🔲 PlannedReturns Include chain for FromEntity
WithRequiredIncludes<TDto>()🔲 PlannedApplies required includes to query

Note: Auto-Include features require DomainEntity metadata (not yet implemented). See mapping-ecosystem.md for architecture details.