Skip to main content
Version: Next

DTO and Entity Mapping Configuration

Files referenced in this document

Table of Contents​

  1. Introduction
  2. Core Mapping Configuration
  3. Forward Mapping: Entity to DTO
  4. Reverse Mapping: DTO to Entity
  5. Advanced Mapping Features
  6. Automatic Conversion Support for Paged Results
  7. Security Handling for Sensitive Fields
  8. Mapping Error Debugging Methods
  9. Best Practice Recommendations
  10. Conclusion

Introduction​

This document detailedly explains the AutoMapper configuration rules defined in MyEntityNameAutoMapperProfile, covering forward mapping from MyEntityName entity to MyEntityNameDto, and reverse mapping from MyEntityNameCreateOrUpdateDtoBase to MyEntityName. It also elucidates the usage scenarios and implementation methods of advanced features like field ignoring, custom conversion, and conditional mapping, and explains how to ensure the security of sensitive fields such as audit information.

Core Mapping Configuration​

The MyEntityNameAutoMapperProfile class inherits from AutoMapper.Profile and defines mapping relationships between types via the CreateMap<TSource, TDestination> method in its constructor. This configuration supports the ABP framework's Extra Properties and Concurrency Stamp, ensuring data integrity and extensibility.

Section sources

Forward Mapping: Entity to DTO​

Forward mapping defines the conversion rules from the domain entity MyEntityName to the data transfer object MyEntityNameDto. This mapping is established via CreateMap<MyEntityName, MyEntityNameDto> and sets MemberList.None to allow mapping of all public members.

The MapExtraProperties option is enabled during the mapping process with the parameter MappingPropertyDefinitionChecks.None, indicating that ABP's extra properties (such as dynamic properties) are included during mapping, and property definition checks are skipped to enhance flexibility.

Mapped Fields Description​

  • Code: Number field, directly mapped
  • Name: Name field, directly mapped
  • Sort: Sorting field, directly mapped
  • Remark: Remark field, directly mapped
  • IsDisabled: Disabled status, nullable boolean
  • ConcurrencyStamp: Concurrency control stamp, used for optimistic locking mechanism

Diagram sources

Section sources

Reverse Mapping: DTO to Entity​

Reverse mapping is implemented via the base class MyEntityNameCreateOrUpdateDtoBase, which is inherited by MyEntityNameCreateDto and MyEntityNameUpdateDto. Although reverse mapping is not explicitly defined in the current configuration, it can be added by extending CreateMap:

CreateMap<MyEntityNameCreateOrUpdateDtoBase, MyEntityName>()
.ForMember(dest => dest.Id, opt => opt.Ignore()) // Ignore Id when creating
.ForMember(dest => dest.CreationTime, opt => opt.Ignore())
.ForMember(dest => dest.CreatorId, opt => opt.Ignore())
.ForMember(dest => dest.LastModificationTime, opt => opt.Condition(src => src.Id != default))
.ForMember(dest => dest.LastModifierId, opt => opt.Condition(src => src.Id != default));

This type of mapping ensures:

  • Id, creation time, and creator are ignored when creating a new entity.
  • Modification time and modifier are updated only when Id exists during update.

Section sources

Advanced Mapping Features​

Field Ignoring (Ignore)​

Use .ForMember(..., opt => opt.Ignore()) to exclude specific fields from mapping. Commonly used for:

  • Entity generated fields (e.g., Id, CreationTime)
  • Read-only properties
  • Sensitive information (e.g., passwords, keys)

Custom Conversion (Using)​

Specify custom conversion logic via .ConvertUsing<ConverterType>() or .Using(), applicable for:

  • Enum and string conversion
  • Time formatting
  • Encrypting/Decrypting fields

Conditional Mapping (Condition)​

Use .Condition() to define mapping prerequisites, for example:

.ForMember(dest => dest.LastModifierId, opt => opt.Condition(src => src.Id != default))

Ensures modifier information is set only during update operations.

Section sources

Automatic Conversion Support for Paged Results​

PagedResultDto<T> in the ABP framework can automatically combine with IQueryable<T>. Once MyEntityNameDto is correctly mapped, pagination conversion can be achieved as follows:

var query = await _repository.GetQueryableAsync();
var totalCount = await query.CountAsync();
var entities = await query.PageBy(input).ToListAsync();
var dtos = ObjectMapper.Map<List<MyEntityName>, List<MyEntityNameDto>>(entities);

return new PagedResultDto<MyEntityNameDto>(totalCount, dtos);

This pattern implements automatic encapsulation and mapping of pagination results without additional configuration.

Section sources

Security Handling for Sensitive Fields​

To protect audit fields (e.g., creation/modification time, user ID) from client tampering, the following measures should be taken:

  1. Ignore Writes During Mapping: Use Ignore() to exclude CreationTime, CreatorId, etc., in DTO to Entity mapping.
  2. Service Layer Assignment: Automatically populate audit information via CurrentUser and Clock in the application service.
  3. Verify Concurrency Stamp: Use ConcurrencyStamp to prevent concurrent modification conflicts.

Diagram sources

Mapping Error Debugging Methods​

Common Error Types​

  • Missing Type Map Configuration: Mapping relationship not defined
  • Unmapped Members: Unmapped members exist
  • Type Mismatch: Conversion failure due to type mismatch

Debugging Steps​

  1. Enable Detailed Exceptions: Turn on Mapper.AssertConfigurationIsValid() in the development environment.
  2. Check Unmapped Members: Use AssertConfigurationIsValid() to verify configuration integrity.
  3. Logging: Log source and target object structures.
  4. Unit Testing: Write mapping test cases to verify bidirectional conversion.

Diagram sources

Best Practice Recommendations​

  1. Separate Mapping Configuration: Split mapping configurations for different modules into multiple Profile classes in complex systems.
  2. Unified Naming Convention: Maintain naming consistency between entities and DTOs for easy identification.
  3. Avoid Circular References: Pay attention to prevent serialization issues caused by navigation properties when designing DTOs.
  4. Performance Optimization: Use ProjectTo<T>() for high-frequency calling interfaces to project directly at the database end.
  5. Version Compatibility: Consider backward compatibility when changing DTOs to avoid breaking existing APIs.

Conclusion​

MyEntityNameAutoMapperProfile achieves efficient conversion between entities and DTOs through concise configuration, ensuring extensibility and security combined with ABP framework features. Reasonable use of advanced functions like field ignoring and conditional mapping can effectively control data flow and protect sensitive information. It is recommended to continuously verify mapping configurations during development and ensure the correctness of conversion logic through unit testing.