You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中避免为不同DTO类重复填充CreatedDate属性

实现CreatedDate属性自动填充的几种方案

方法一:使用AutoMapper简化投影

AutoMapper的ProjectTo方法可以直接将EF Core查询结果映射到DTO,自动处理继承基类的属性映射,无需手动赋值CreatedDate。

  1. 定义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基类

  1. 在查询中替换手动构造为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的赋值逻辑:

  1. 编写扩展方法:
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
        );
    }
}
  1. 在查询中使用扩展方法:
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,可以定义通用基类投影表达式,减少重复代码:

  1. 定义基类投影表达式:
public static class BaseProjections
{
    public static readonly Expression<Func<BaseEntity, DateTimeGetDto>> BaseDtoMap = 
        entity => new DateTimeGetDto { CreatedDate = entity.CreatedDate };
}
  1. 在查询中复用表达式逻辑:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 21:10:45