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
| Symbol | Meaning |
|---|
| ✅ | Implemented & Tested |
| ⚠️ | Implemented, needs fix |
| ❌ | Not implemented |
| 🔲 | Planned |
| Type Kind | FromEntity | ToEntity | Projection | Test File |
|---|
class | ✅ | ✅ | ✅ | NullableAndNestedGeneratorTests.PartialClass_GeneratesCorrectly |
record | ✅ | ✅ | ✅ | BasicMappingGeneratorTests |
struct | ✅ | 🔲 | 🔲 | NullableAndNestedGeneratorTests.PartialStruct_GeneratesCorrectly |
record struct | ✅ | 🔲 | 🔲 | BasicMappingGeneratorTests.MapFrom_RecordStruct_GeneratesCorrectly |
| Source Type Kind | Support | Test |
|---|
class | ✅ | All basic tests |
record | ✅ | - |
struct | ✅ | NullableAndNestedGeneratorTests.PartialStruct_GeneratesCorrectly |
record struct | ✅ | - |
Note: Null check skipped for value types (structs can’t be null).
| Type | Direct Mapping | Test |
|---|
int | ✅ | BasicMappingGeneratorTests |
int? | ✅ | NullableAndNestedGeneratorTests.NullableInt_MapsDirectly |
string | ✅ | Multiple tests |
string? | ✅ | NullableAndNestedGeneratorTests.NullableString_MapsDirectly |
decimal | ✅ | NullableAndNestedGeneratorTests.PartialClass_GeneratesCorrectly |
DateTime | ✅ | - |
DateTime? | ✅ | NullableAndNestedGeneratorTests.NullableDateTime_MapsDirectly |
Guid | ✅ | - |
Guid? | ✅ | TypeConversionGeneratorTests.NullableGuid_MapsDirectly |
DateOnly | ✅ | TypeConversionGeneratorTests.DateOnly_MapsDirectly |
TimeOnly | ✅ | TypeConversionGeneratorTests.DateOnly_MapsDirectly |
DateOnly? | ✅ | TypeConversionGeneratorTests.NullableDateOnly_MapsDirectly |
TimeOnly? | ✅ | TypeConversionGeneratorTests.NullableDateOnly_MapsDirectly |
enum | ✅ | TypeConversionGeneratorTests.Enum_SameType_MapsDirectly |
enum? | ✅ | TypeConversionGeneratorTests.NullableEnum_MapsDirectly |
| Collection Type | Simple Element | DTO Element | Test |
|---|
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 |
| Scenario | Status | Test |
|---|
| Single non-nullable DTO | ✅ | NullableAndNestedGeneratorTests.NestedDto_MapsWithFromEntity |
| Single nullable DTO | ✅ | NullableAndNestedGeneratorTests.NullableNestedDto_HandlesNullSafely |
| Array of DTO | ✅ | NullableAndNestedGeneratorTests.ArrayOfNestedDto_MapsEachElement |
| List of DTO | ✅ | CollectionMappingGeneratorTests.ListOfDto_MapsEachElement |
| List of nullable DTO | ✅ | NullableAndNestedGeneratorTests.NullableListOfNullableNestedDto_HandlesCorrectly |
Implementation: Uses SymbolDisplayFormat.FullyQualifiedFormat for type names to avoid namespace resolution issues.
| Dictionary Type | Simple Value | DTO Value | Test |
|---|
Dictionary<K,V> | ✅ | ✅ | CollectionMappingGeneratorTests.DictionaryStringInt, TypeConversionGeneratorTests.DictionaryWithDtoValue |
IDictionary<K,V> | 🔲 | 🔲 | - |
IReadOnlyDictionary<K,V> | 🔲 | 🔲 | - |
| Conversion | Status | Test |
|---|
int → long | ✅ | TypeConversionGeneratorTests.IntToLong_ImplicitConversion |
int → decimal | ✅ | TypeConversionGeneratorTests.IntToDecimal_ImplicitConversion |
int? → int (no default) | ⚠️ CS0266 | TypeConversionGeneratorTests.NullableIntToInt_WithoutDefault_ShouldCompile |
int? → int (with default) | ✅ | AdvancedMappingGeneratorTests.MapProperty_WithDefault_UsesDefaultWhenNull |
Note: C# implicit conversions (widening) work automatically. Nullable → Non-nullable requires [MapProperty(Default=)].
| Conversion | Status | Generated Code | Test |
|---|
int → string | ✅ | .ToString() | TypeConversionGeneratorTests.IntToString |
string → int | ✅ | int.Parse() | TypeConversionGeneratorTests.StringToInt |
enum → string | ✅ | .ToString() | TypeConversionGeneratorTests.EnumToString |
string → enum | ✅ | Enum.Parse<T>() | TypeConversionGeneratorTests.StringToEnum |
Guid → string | ✅ | .ToString() | TypeConversionGeneratorTests.GuidToString |
string → Guid | ✅ | Guid.Parse() | TypeConversionGeneratorTests.StringToGuid |
DateTime → DateOnly | ✅ | DateOnly.FromDateTime() | TypeConversionGeneratorTests.DateTimeToDateOnly |
DateOnly → DateTime | ✅ | .ToDateTime(TimeOnly.MinValue) | TypeConversionGeneratorTests.DateOnlyToDateTime |
DateTime → TimeOnly | ✅ | TimeOnly.FromDateTime() | TypeConversionGeneratorTests.DateTimeToTimeOnly |
decimal → string | ✅ | .ToString() | TypeConversionGeneratorTests.DecimalToString |
string → decimal | ✅ | decimal.Parse() | TypeConversionGeneratorTests.StringToDecimal |
bool → string | ✅ | .ToString() | TypeConversionGeneratorTests.BoolToString |
string → bool | ✅ | bool.Parse() | TypeConversionGeneratorTests.StringToBool |
DateTime → string | ✅ | .ToString() | TypeConversionGeneratorTests.DateTimeToString |
string → DateTime | ✅ | DateTime.Parse() | TypeConversionGeneratorTests.StringToDateTime |
string → DateOnly | ✅ | DateOnly.Parse() | TypeConversionGeneratorTests.StringToDateOnly |
string → TimeOnly | ✅ | TimeOnly.Parse() | TypeConversionGeneratorTests.StringToTimeOnly |
Implementation: Generator detects source/target type mismatch and applies known conversion patterns automatically.
Nullable variants also supported (e.g., int? → string, string → int?).
| Source → Target | Status | Test |
|---|
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 |
| Attribute | Status | Test |
|---|
[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.* |
| Strategy | Status | Test |
|---|
| Direct name match | ✅ | All basic tests |
| Case-insensitive match | ✅ | - |
Flattening (AddressCity → Address.City) | ✅ | AdvancedMappingGeneratorTests.Flattening_* |
Concatenation (FullName → FirstName + LastName) | ✅ | BasicMappingGeneratorTests.MapFrom_WithFullNameConvention |
Explicit path via [MapProperty] | ✅ | AdvancedMappingGeneratorTests.MapProperty_* |
| Feature | Status | Test |
|---|
| ID property exclusion in ToEntity | ✅ | AdvancedMappingGeneratorTests.MapTo_ExcludesIdByDefault |
| Init-only properties | ✅ | - |
| Required properties | ✅ | - |
| Circular reference detection | ✅ | - |
| Null safety | ✅ | NullableAndNestedGeneratorTests.* |
| Method | Status | Struct Support | Test |
|---|
FromEntity(entity) | ✅ | ✅ | All FromEntity tests |
ToEntity() | ✅ | 🔲 | MapTo tests |
Projection | ✅ | 🔲 | ProjectionGeneratorTests |
Note: ApplyTo() functionality moved to Pragmatic.Domain as [Mutation<T>] attribute.
| Hook | Status | Test |
|---|
partial void BeforeMapping() | ✅ | - |
partial void CustomizeMapping() | ✅ | - |
MappingContext struct | ✅ | - |
| DTO Accessibility | Support | Extensions Class | Test |
|---|
public | ✅ | public static | All basic tests |
internal | ✅ | internal static | AdvancedMappingGeneratorTests.MapFrom_InternalClass_GeneratesInternalMethods |
private (nested) | 🔲 | - | - |
| Bug | Status | Fix |
|---|
Struct source + Ensure.ThrowIfNull | ✅ FIXED | Skip null check for value types |
Nullable DTO type name includes ? | ✅ FIXED | Use SymbolDisplayFormat.FullyQualifiedFormat |
List<string> treated as DTO collection | ✅ FIXED | Check IsElementSimple in AnalyzeNestedDto |
Extensions class ignores accessibility | ✅ FIXED | Added ParseAccessibility() in MappingExtensionsTemplate |
[MapProperty(Default=)] not implemented | ✅ FIXED | Added fallback resolution by property name when only Default is specified |
| Issue | Status | Fix | Test |
|---|
[MapProperty(Format=)] for non-DateTime | ✅ FIXED | Added format support to GenerateNumericToString and GenerateToString | AdvancedMappingGeneratorTests.MapProperty_WithFormat_* |
[MapProperty] + [MapConverter] together | ✅ FIXED | Moved converter check before MapProperty check, passed converter to CreateExplicitMapping | AdvancedMappingGeneratorTests.MapProperty_WithMapConverter_* |
| Test File | Tests | Passing | Failing |
|---|
BasicMappingGeneratorTests | 7 | 7 | 0 |
AdvancedMappingGeneratorTests | 16 | 16 | 0 |
CollectionMappingGeneratorTests | 9 | 9 | 0 |
ProjectionGeneratorTests | 5 | 5 | 0 |
NullableAndNestedGeneratorTests | 9 | 9 | 0 |
TypeConversionGeneratorTests | 51 | 51 | 0 |
AutomaticConversionGeneratorTests | 12 | 12 | 0 |
AutoDefaultGeneratorTests | 12 | 12 | 0 |
DiagnosticTests | 4 | 4 | 0 |
| TOTAL | 125 | 125 | 0 |
Note: EF Core integration tests use TestContainers with PostgreSQL.
| Sample File | Features Demonstrated |
|---|
BasicMappingSample | FromEntity, extension methods, collection mapping, FullName concatenation, flattening |
NestedMappingSample | Nested DTOs, collection of DTOs, flattened DTO |
BidirectionalMappingSample | MapFrom + MapTo, ToEntity() |
StructMappingSample | record struct, zero-allocation, Projection |
ProjectionSample | GenerateProjection, Expression<Func<T,TDto>> |
TypeConversionSample | ToString, Parse, DateTime↔DateOnly, Dictionary with DTOs, Inheritance |
NullableAndAdvancedSample | Auto-default, Collection type conversions, Circular references, DateOnly→DateTime |
TypeCombinationsSample | class→class, class→record, record→record, record→class, MapIgnore |
AdvancedAttributesSample | MapIgnore, 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
| Feature | Description | Status |
|---|
| Auto-default for primitives | int? → int uses GetValueOrDefault(), string? → string uses ?? "" | ✅ Implemented |
| Auto-default in Projection | Uses ?? 0, ?? "", ?? Guid.Empty for EF Core Expression Tree compatibility | ✅ Implemented |
| Feature | Description | Status | Test |
|---|
| ToString conversions | int → string via .ToString() | ✅ | TypeConversionGeneratorTests.IntToString |
| Enum → string | Status.Active → "Active" | ✅ | TypeConversionGeneratorTests.EnumToString |
| Parse conversions | string → int via int.Parse() | ✅ | TypeConversionGeneratorTests.StringToInt |
| Guid ↔ string | Guid.ToString() / Guid.Parse() | ✅ | TypeConversionGeneratorTests.GuidToString/StringToGuid |
| Feature | Description | Status | Test |
|---|
| DateTime → DateOnly | DateOnly.FromDateTime() | ✅ | TypeConversionGeneratorTests.DateTimeToDateOnly |
| DateTime → TimeOnly | TimeOnly.FromDateTime() | ✅ | TypeConversionGeneratorTests.DateTimeToTimeOnly |
| DateOnly → DateTime | .ToDateTime(TimeOnly.MinValue) | ✅ | TypeConversionGeneratorTests.DateOnlyToDateTime |
| String ↔ decimal | Parse/ToString | ✅ | TypeConversionGeneratorTests.StringToDecimal/DecimalToString |
| Feature | Description | Status | Test |
|---|
| Dictionary with DTO values | Dictionary<string, CategoryDto> | ✅ | TypeConversionGeneratorTests.DictionaryWithDtoValue |
| Inheritance mapping | Base → Derived DTO properties | ✅ | TypeConversionGeneratorTests.InheritedProperties |
| Interface-based DTOs | IUserDto | 🔲 | Future |
| Scenario | Category | Test File | Status |
|---|
| Same-name property mapping | Basic | BasicMappingGeneratorTests | ✅ |
| Different-name property mapping | Advanced | AdvancedMappingGeneratorTests | ✅ |
| Custom converter | Advanced | AdvancedMappingGeneratorTests | ✅ |
| Nested DTO mapping | Nested | NullableAndNestedGeneratorTests | ✅ |
| Collection of DTOs | Collection | CollectionMappingGeneratorTests | ✅ |
| Scenario | Test | Status |
|---|
| Non-partial class skips generation | DiagnosticTests.NonPartialClass_SkipsGeneration | ✅ |
| Partial class generates correctly | DiagnosticTests.PartialClass_GeneratesCorrectly | ✅ |
| Unmatched property uses default | DiagnosticTests.UnmatchedProperty_GeneratesWithDefault | ✅ |
| Invalid MapProperty path | DiagnosticTests.MapProperty_WithInvalidPath_CompilesButUnmapped | ✅ |
| [GenerateProjection] without [MapFrom] | DiagnosticTests.GenerateProjection_WithoutMapFrom_SkipsProjection | ✅ |
| [MapIgnore] takes precedence | DiagnosticTests.MapIgnore_TakesPrecedence_OverMapProperty | ✅ |
| Nested DTO with [MapFrom] | DiagnosticTests.NestedDto_WithMapFrom_GeneratesCorrectly | ✅ |
| Collection with simple elements | DiagnosticTests.Collection_WithSimpleElements_MapsDirectly | ✅ |
| Struct source skips null check | DiagnosticTests.StructSource_SkipsNullCheck | ✅ |
| Class source includes null check | DiagnosticTests.ClassSource_IncludesNullCheck | ✅ |
| MapTo excludes ID by default | DiagnosticTests.MapTo_ExcludesIdByDefault | ✅ |
| Internal class generates internal extensions | DiagnosticTests.InternalClass_GeneratesInternalExtensions | ✅ |
| Empty DTO generates minimal | DiagnosticTests.EmptyDto_GeneratesMinimalMapping | ✅ |
| Multiple [MapFrom] causes error | DiagnosticTests.MultipleMapFrom_CausesDuplicateAttributeError | ✅ |
| Bidirectional mapping | DiagnosticTests.MapFrom_And_MapTo_OnSameType_GeneratesBothMethods | ✅ |
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
var dtos = users.ToUserDto();
// ✅ SOLUTION 2: Use Projection (BEST - optimized SQL)
var dtos = await _db.Users
.Select(UserDto.Projection)
| Feature | Status | Description |
|---|
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
.ToListDtoAsync(UserDto.Projection);
var page = await _db.Users
.ToPagedDtoAsync(UserDto.Projection, pageNumber: 1, pageSize: 20);
// page.Items, page.TotalCount, page.TotalPages, page.HasNextPage, etc.
| Feature | Status | Description |
|---|
RequiredIncludes<TDto>() | 🔲 Planned | Returns Include chain for FromEntity |
WithRequiredIncludes<TDto>() | 🔲 Planned | Applies required includes to query |
Note: Auto-Include features require DomainEntity metadata (not yet implemented).
See mapping-ecosystem.md for architecture details.