如何在C#中避免为不同DTO类重复填充CreatedDate属性
实现CreatedDate属性自动填充的几种方案
方法一:使用AutoMapper简化投影
AutoMapper的ProjectTo方法可以直接将EF Core查询结果映射到DTO,自动处理继承基类的属性映射,无需手动赋值CreatedDate。
- 定义AutoMapper配置文件:
public class MappingProfile : Profile { public MappingProfile() { // 为基类实体和基类DTO创建映射规则 CreateMap<BaseEntity, DateTimeGetDto>() .ForMember(dest => dest.CreatedDate, opt => opt.MapFrom(src => src.CreatedDate)); // 具体实体与DTO的映射会自动继承基类规则 CreateMap<Town, TownGetDto>(); CreateMap<Article, ArticleGetDto>(); // 其他实体与DTO的映射同理添加 } }
注:假设所有数据库实体都继承了包含CreatedDate的BaseEntity基类
- 在查询中替换手动构造为
ProjectTo:
public async Task<List<TownGetDto>> GetTownsAsync(CancellationToken cancellationToken) { var towns = await _dbContext.Towns .ProjectTo<TownGetDto>(_mapper.ConfigurationProvider) .ToListAsync(cancellationToken); return towns; }
AutoMapper会自动完成CreatedDate的赋值,无需在Select中手动指定。
方法二:自定义EF Core投影扩展方法
如果不想引入AutoMapper,可以写一个通用扩展方法复用CreatedDate的赋值逻辑:
- 编写扩展方法:
public static class ProjectionExtensions { public static Expression<Func<TEntity, TDto>> WithCreatedDate<TEntity, TDto>(this Expression<Func<TEntity, TDto>> baseSelector) where TEntity : BaseEntity where TDto : DateTimeGetDto { var createdDateProp = typeof(TDto).GetProperty(nameof(DateTimeGetDto.CreatedDate)); var entityCreatedDate = Expression.Property(baseSelector.Parameters[0], nameof(BaseEntity.CreatedDate)); var memberInit = (MemberInitExpression)baseSelector.Body; var updatedBindings = memberInit.Bindings.Append( Expression.Bind(createdDateProp, entityCreatedDate) ); return Expression.Lambda<Func<TEntity, TDto>>( Expression.MemberInit(memberInit.NewExpression, updatedBindings), baseSelector.Parameters ); } }
- 在查询中使用扩展方法:
public async Task<List<TownGetDto>> GetTownsAsync(CancellationToken cancellationToken) { var towns = await _dbContext.Towns .Select(x => new TownGetDto { Id = x.Id, Title = x.Title, DialingCode = x.DialingCode, ZipCode = x.ZipCode, CountryId = x.CountryId }.WithCreatedDate<Town, TownGetDto>()) .ToListAsync(cancellationToken); return towns; }
只需编写DTO的特有属性,CreatedDate会通过扩展方法自动赋值。
方法三:基类表达式复用
如果所有实体都继承BaseEntity,可以定义通用基类投影表达式,减少重复代码:
- 定义基类投影表达式:
public static class BaseProjections { public static readonly Expression<Func<BaseEntity, DateTimeGetDto>> BaseDtoMap = entity => new DateTimeGetDto { CreatedDate = entity.CreatedDate }; }
- 在查询中复用表达式逻辑:
public async Task<List<TownGetDto>> GetTownsAsync(CancellationToken cancellationToken) { var towns = await _dbContext.Towns .Select(x => new TownGetDto { Id = x.Id, Title = x.Title, DialingCode = x.DialingCode, ZipCode = x.ZipCode, CountryId = x.CountryId, CreatedDate = BaseProjections.BaseDtoMap.Compile()(x) }) .ToListAsync(cancellationToken); return towns; }
这种方式避免了重复编写x.CreatedDate,后续基类属性变更时只需修改基类表达式即可。
内容的提问来源于stack exchange,提问作者Roxy'Pro
相关产品推荐
相关产品推荐

