DTO and Entity Mapping Configuration
Files referenced in this document
- MyEntityNameAutoMapperProfile.cs
- MyEntityNameDto.cs
- MyEntityNameCreateOrUpdateDtoBase.cs
- MyEntityNameCreateDto.cs
- MyEntityNameUpdateDto.cs
- MyEntityName.cs
Table of Contents
- Introduction
- Core Mapping Configuration
- Forward Mapping: Entity to DTO
- Reverse Mapping: DTO to Entity
- Advanced Mapping Features
- Automatic Conversion Support for Paged Results
- Security Handling for Sensitive Fields
- Mapping Error Debugging Methods
- Best Practice Recommendations
- 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 mappedName: Name field, directly mappedSort: Sorting field, directly mappedRemark: Remark field, directly mappedIsDisabled: Disabled status, nullable booleanConcurrencyStamp: 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
Idexists 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:
- Ignore Writes During Mapping: Use
Ignore()to excludeCreationTime,CreatorId, etc., in DTO to Entity mapping. - Service Layer Assignment: Automatically populate audit information via
CurrentUserandClockin the application service. - Verify Concurrency Stamp: Use
ConcurrencyStampto 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
- Enable Detailed Exceptions: Turn on
Mapper.AssertConfigurationIsValid()in the development environment. - Check Unmapped Members: Use
AssertConfigurationIsValid()to verify configuration integrity. - Logging: Log source and target object structures.
- Unit Testing: Write mapping test cases to verify bidirectional conversion.
Diagram sources
Best Practice Recommendations
- Separate Mapping Configuration: Split mapping configurations for different modules into multiple Profile classes in complex systems.
- Unified Naming Convention: Maintain naming consistency between entities and DTOs for easy identification.
- Avoid Circular References: Pay attention to prevent serialization issues caused by navigation properties when designing DTOs.
- Performance Optimization: Use
ProjectTo<T>()for high-frequency calling interfaces to project directly at the database end. - 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.