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

如何在AutoMapper中基于UserId实现带权限的文档收藏状态映射

解决AutoMapper动态映射IsFavourited字段的问题

核心需求

  • 角色1用户:返回的DocumentDto中IsFavourited字段为null
  • 角色2用户:返回的DocumentDto中IsFavourited字段根据该用户是否收藏文档返回true/false
  • 不能过滤文档数据,仅动态调整字段值

可行方案

方案1:利用AutoMapper上下文参数传递用户信息

这种方式兼容内存映射和EF Core投影,且无需修改数据库设计。

1.1 配置映射规则
public class DocumentProfile : Profile
{
    public DocumentProfile()
    {
        CreateMap<Document, DocumentDto>()
            .ForMember(dest => dest.IsFavourited, opt => opt.MapFrom((src, dest, _, context) => 
            {
                // 从上下文获取用户信息
                var userId = context.Items.TryGetValue("UserId", out var userIdObj) ? (long)userIdObj : (long?)null;
                var isRole2 = context.Items.TryGetValue("IsRole2", out var roleObj) ? (bool)roleObj : false;

                // 根据角色和用户ID判断返回值
                if (!isRole2 || userId == null)
                    return null;
                
                // EF Core会自动翻译为Exists查询,无需Include所有Favourites
                return src.Favourites.Any(f => f.UserId == userId);
            }));
    }
}
1.2 在CQRS处理器中传递用户信息
// 假设已通过权限校验获取当前用户ID和角色
long currentUserId = ...;
bool isRole2 = ...;

// 内存映射场景(已从数据库加载Document数据)
var documents = await _context.Documents.ToListAsync();
var dtos = _mapper.Map<List<DocumentDto>>(documents, opt => 
{
    opt.Items["UserId"] = currentUserId;
    opt.Items["IsRole2"] = isRole2;
});

// EF Core投影场景(直接在数据库层面完成映射,性能更优)
var dtos = await _context.Documents
    .ProjectTo<DocumentDto>(_mapper.ConfigurationProvider, 
        new { UserId = currentUserId, IsRole2 = isRole2 })
    .ToListAsync();

方案2:注入当前用户服务到AutoMapper Profile

如果项目中已有获取当前用户的服务(如ICurrentUserService),可直接注入到Profile中:

2.1 定义当前用户服务
public interface ICurrentUserService
{
    long? UserId { get; }
    bool IsRole2 { get; }
}

// 实现类(可通过IHttpContextAccessor获取请求上下文信息)
public class CurrentUserService : ICurrentUserService
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public CurrentUserService(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public long? UserId => long.TryParse(_httpContextAccessor.HttpContext?.User.FindFirstValue(ClaimTypes.NameIdentifier), out var id) ? id : null;
    public bool IsRole2 => _httpContextAccessor.HttpContext?.User.IsInRole("Role2") ?? false;
}
2.2 配置映射规则
public class DocumentProfile : Profile
{
    public DocumentProfile(ICurrentUserService currentUserService)
    {
        CreateMap<Document, DocumentDto>()
            .ForMember(dest => dest.IsFavourited, opt => opt.MapFrom(src => 
            {
                if (!currentUserService.IsRole2 || currentUserService.UserId == null)
                    return null;
                
                return src.Favourites.Any(f => f.UserId == currentUserService.UserId);
            }));
    }
}
2.3 在CQRS处理器中直接映射
// 内存映射
var documents = await _context.Documents.ToListAsync();
var dtos = _mapper.Map<List<DocumentDto>>(documents);

// EF Core投影
var dtos = await _context.Documents
    .ProjectTo<DocumentDto>(_mapper.ConfigurationProvider)
    .ToListAsync();

关键说明

  • 数据库设计无问题:一对多的收藏关系是合理的,无需调整
  • 避免加载无关数据:使用Any()代替Include(Favourites),EF会自动生成高效的Exists查询,不会加载其他用户的收藏记录
  • 兼容现有业务:无需修改分页、过滤器等逻辑,仅在映射层动态处理字段值

内容的提问来源于stack exchange,提问作者Radek L

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 17:40:28