Skip to content

Case Study: The Full-Features Demo ​

This walkthrough covers the ultimate "Full-Features" sample application that demonstrates every major mechanism of AutoMappic v0.6.0 in action.

Scenario: Complex Entity Synchronization ​

Our goal is to map a domain-driven User model to a DTO, perform updates on a collection of Project Tasks, and then sync those changes back to the original database entity using Smart-Sync.


The Implementation ​

1. The Mapping Profile ​

The profile defines our rules, including flattening, custom mapping for masked emails, and synchronization logic.

csharp
public class FullFeaturesProfile : Profile
{
    public FullFeaturesProfile()
    {
        // Opt-in to the v0.5.0 synchronization engine
        EnableIdentityManagement = true;
        EnableEntitySync = true;

        CreateMap<User, UserDto>()
            .ForMember(d => d.AddressCity, opt => opt.MapFrom(s => s.Address != null ? s.Address.City : "Unknown"))
            .ForMember(d => d.Email, opt => opt.MapFrom(src => UserConverters.MaskEmail(src.Email)))
            .BeforeMap((src, dest) => {
                src.AuditLog = $"Last mapped at {DateTime.Now}";
            });

        // Enable Smart-Sync for Projects and Tasks via ReverseMap
        CreateMap<Project, ProjectDto>().ReverseMap();
        CreateMap<TaskItem, TaskItemDto>().ReverseMap();
    }
}

2. The Execution Logic ​

We set up a simple console app that walks through basic mapping, cyclic awareness, and identity-aware collection syncing.

csharp
public static void Main()
{
    Console.WriteLine("--- AutoMappic v0.6.0: The Full Features Demo ---\n");

    // 1. Setup DI (Zero startup cost)
    var services = new ServiceCollection();
    services.AddAutoMappic(new FullFeaturesProfile());
    var provider = services.BuildServiceProvider();
    var mapper = provider.GetRequiredService<IMapper>();

    // 2. Demo: Smart-Sync
    var project = new Project {
        Id = 1, Name = "Build House",
        Tasks = new List<TaskItem> { 
            new TaskItem { Id = 1, Description = "Foundation", IsDone = true },
            new TaskItem { Id = 2, Description = "Walls", IsDone = false }
        }
    };

    var dto = mapper.Map<Project, ProjectDto>(project);
    dto.Tasks[0].Description = "Foundation (Reinforced)";
    dto.Tasks.Add(new TaskItemDto { Id = 3, Description = "Roof", IsDone = false });

    // Sync DTO back to Project in-place - preserving identities!
    mapper.Map(dto, project);
}

Sample Output ​

When running the full sample, the following output is generated, showing Smart-Sync preserving original entity instances while applying DTO updates:

text
--- AutoMappic v0.5.0: The Full Features Demo ---

[1] BASIC MAPPING + FLATTENING + CONVERTERS
   User: Alice (a***@example.com)
   Flattened Address: Paris
   Enum -> String: Active
   Lifecycle Audit: Last mapped at 3/30/2026 7:27:59 PM

[2] CIRCULAR GRAPH (IDENTITY MANAGEMENT)
   Main: Main Task (Updated)
   Circular awareness is handled automatically by the generator diagnostics.

[3] SMART-SYNC (COLLECTION SYNCHRONIZATION)
   [HOOK: AfterMap] Mapping Project 'Build House' with 2 tasks.
   Project: Build House with 2 tasks.
   After Sync (In-Place Update):
     - Task #1: Foundation (Reinforced) [Done: True]
     - Task #2: Walls [Done: False]
     - Task #3: Roof [Done: False]
   Collection preserved original list instance: True

--- Demo Complete! ---

Tips & Lessons Learned ​

While building this sample, we encountered several common developer pitfalls that AutoMappic's diagnostic engine caught at compile-time:

1. Bidirectional Mapping Integrity (AM0001) ​

When using .ReverseMap(), AutoMappic enforces 100% coverage in both directions. If your destination model (User) has domain-only properties like Address and AuditLog that are not present in your DTO, the build will fail with AM0001.

  • Resolution: Always use .ForMemberIgnore() on the reverse profile to explicitly acknowledge domain-only fields.

2. Single Source of Truth (AM0009) ​

AutoMappic prevents defining the same mapping twice in a profile (e.g., mapping User $\to$ UserDto in two different locations). This ensures that interceptors are deterministic.

  • Resolution: Combine all configuration for a specific type-pair into a single CreateMap block.

3. Cyclic Reference Awareness (AM0006) ​

Even with Identity Management enabled, the source generator will warn you (AM0006) if it detects a potential infinite loop in your static object graph.

  • Pro-Tip: While Identity Management handles this at runtime, these warnings are essential for performance hygiene—they remind you to keep DTO graphs shallow whenever possible.

4. Interceptor Overload Resolution ​

Interceptors replace standard Map<TSource, TDestination> calls. If you need to use advanced generated features (like passing a specific MappingContext), you can call the generated extension methods directly or rely on the mapper's automatic context creation for collections.


The Technology Behind the Scenes ​

By migrating these features to Roslyn Interceptors, AutoMappic v0.6.0 achieves:

  • Zero Startup Lag: No reflection-based profile scanning.
  • Extreme Performance: 1.45x faster throughout than traditional JIT mappers.
  • Native AOT Ready: 100% compatible with trimming and single-file publication.

You can find the full source code for this demo in the AutoMappic GitHub Repository.